UltraScan III
us_edit.cpp
Go to the documentation of this file.
1 
3 #include <QApplication>
4 #include <QDomDocument>
5 
6 #include "us_edit.h"
7 #include "us_license_t.h"
8 #include "us_license.h"
9 #include "us_settings.h"
10 #include "us_gui_settings.h"
11 #include "us_investigator.h"
12 #include "us_run_details2.h"
13 #include "us_exclude_profile.h"
14 #include "us_select_lambdas.h"
15 #include "us_ri_noise.h"
16 #include "us_edit_scan.h"
17 #include "us_math2.h"
18 #include "us_util.h"
19 #include "us_load_auc.h"
20 #include "us_passwd.h"
21 #include "us_get_edit.h"
22 #include "us_constants.h"
23 #include "us_images.h"
24 
25 #ifndef DbgLv
26 #define DbgLv(a) if(dbg_level>=a)qDebug()
27 #endif
28 
30 // the class US_FitMeniscus.
31 
32 int main( int argc, char* argv[] )
33 {
34  QApplication application( argc, argv );
35 
36  #include "main1.inc"
37 
38  // License is OK. Start up.
39 
40  US_Edit w;
41  w.show();
42  return application.exec();
43 }
44 
45 // Constructor
47 {
48  check = QIcon( US_Settings::appBaseDir() + "/etc/check.png" );
49  invert = 1.0;
50  all_edits = false;
51  men_1click = US_Settings::debug_match( "men2click" ) ? false : true;
52  total_speeds = 0;
53  total_edits = 0;
54  v_line = NULL;
56  dbP = NULL;
57  chlamb = QChar( 955 );
58 
59  setWindowTitle( tr( "Edit UltraScan Data" ) );
60  setPalette( US_GuiSettings::frameColor() );
61 
62  QVBoxLayout* top = new QVBoxLayout( this );
63  top->setSpacing ( 2 );
64  top->setContentsMargins ( 2, 2, 2, 2 );
65 
66  // Put the Run Info across the entire window
67  QHBoxLayout* runInfo = new QHBoxLayout();
68  QLabel* lb_info = us_label( tr( "Run Info:" ), -1 );
69  runInfo->addWidget( lb_info );
70 
71  le_info = us_lineedit( "", 1, true );
72  runInfo->addWidget( le_info );
73 
74  top->addLayout( runInfo );
75 
76  QHBoxLayout* main = new QHBoxLayout();
77  QVBoxLayout* left = new QVBoxLayout;
78 
79  // Start of Grid Layout
80  QGridLayout* specs = new QGridLayout;
81 
82  // Investigator
83  QPushButton* pb_investigator = us_pushbutton( tr( "Select Investigator" ) );
84 
85  if ( US_Settings::us_inv_level() < 1 )
86  pb_investigator->setEnabled( false );
87 
88  int id = US_Settings::us_inv_ID();
89  QString number = ( id > 0 ) ?
90  QString::number( US_Settings::us_inv_ID() ) + ": "
91  : "";
93  1, true );
94 
95  // Disk/DB control
97 
98  // Load
99  QPushButton*
100  pb_load = us_pushbutton( tr( "Load Data" ) );
101  pb_details = us_pushbutton( tr( "Run Details" ), false );
102 
103  // Triple and Speed Step
104  lb_triple = us_label( tr( "Cell / Channel / Wavelength" ), -1 );
106  lb_rpms = us_label( tr( "Speed Step (RPM) of triple" ), -1 );
107  cb_rpms = us_comboBox();
108  lb_rpms->setVisible( false );
109  cb_rpms->setVisible( false );
110 
111  // Scan Gaps
113  lb_gaps = us_label( tr( "Threshold for Scan Gaps" ), -1 );
114  ct_gaps = us_counter( 1, 10.0, 100.0 );
115  ct_gaps->setStep ( 10.0 );
116  ct_gaps->setValue( 50.0 );
117 
118  // MWL Control
119  QFontMetrics fmet( font );
120  int fwid = fmet.maxWidth();
121  int rhgt = ct_gaps->height();
122  int lwid = fwid * 4;
123  int swid = lwid + fwid;
124  lb_mwlctl = us_banner( tr( "Wavelength Controls" ) );
125  QButtonGroup* r_group = new QButtonGroup( this );
126  QButtonGroup* x_group = new QButtonGroup( this );
127  lo_lrange = us_radiobutton( tr( "Lambda Range" ), rb_lrange,
128  true );
129  lo_custom = us_radiobutton( tr( "Custom Lambda List" ), rb_custom,
130  false );
131  rb_lrange->setFont( font );
132  rb_custom->setFont( font );
133  r_group->addButton( rb_lrange, 0 );
134  r_group->addButton( rb_custom, 1 );
135  lb_ldelta = us_label( tr( "%1 Index Increment:" ).arg( chlamb ), -1 );
136  ct_ldelta = us_counter( 1, 1, 100, 1 );
137  ct_ldelta->setFont( font );
138  ct_ldelta->setStep( 1 );
139  ct_ldelta->setMinimumWidth( lwid );
140  ct_ldelta->resize( rhgt, swid );
141  lb_lstart = us_label( tr( "%1 Start:" ).arg( chlamb ), -1 );
142  lb_lend = us_label( tr( "%1 End:" ).arg( chlamb ), -1 );
143  lb_lplot = us_label( tr( "Plot (W nm):" ), -1 );
144 
145  int nlmbd = 224;
146  int lmbdlo = 251;
147  int lmbdhi = 650;
148  int lmbddl = 1;
149  QString lrsmry = tr( "%1 raw: %2 %3 to %4" )
150  .arg( nlmbd ).arg( chlamb ).arg( lmbdlo ).arg( lmbdhi );
151  le_ltrng = us_lineedit( lrsmry, -1, true );
152  QString lxsmry = tr( "%1 MWL exports: %2 %3 to %4, raw index increment %5" )
153  .arg( nlmbd ).arg( chlamb ).arg( lmbdlo ).arg( lmbdhi ).arg( lmbddl );
154  le_lxrng = us_lineedit( lxsmry, -1, true );
155  cb_lplot = us_comboBox();
157  cb_lend = us_comboBox();
158 
159  cb_lplot ->setFont( font );
160  cb_lstart->setFont( font );
161  cb_lend ->setFont( font );
162 
163  pb_custom = us_pushbutton( tr( "Custom Lambdas" ), false, -1 );
164  pb_incall = us_pushbutton( tr( "Include All Lambdas" ), true, -1 );
165  pb_larrow = us_pushbutton( tr( "previous" ), true, -2 );
166  pb_rarrow = us_pushbutton( tr( "next" ), true, -2 );
169 
170  lo_radius = us_radiobutton( tr( "x axis Radius" ), rb_radius,
171  true );
172  lo_waveln = us_radiobutton( tr( "x axis Wavelength" ), rb_waveln,
173  false );
174  rb_radius->setFont( font );
175  rb_waveln->setFont( font );
176  x_group->addButton( rb_radius, 0 );
177  x_group->addButton( rb_waveln, 1 );
178 
179  QStringList lambdas;
180 lambdas << "250" << "350" << "450" << "550" << "580" << "583" << "650";
181  cb_lplot ->addItems( lambdas );
182  cb_lstart->addItems( lambdas );
183  cb_lend ->addItems( lambdas );
184 
185  cb_lplot ->setCurrentIndex( 2 );
186  cb_lstart->setCurrentIndex( 0 );
187  cb_lend ->setCurrentIndex( 6 );
188 
189  connect_mwl_ctrls( true );
190 
191  // Scan Controls
192  QLabel* lb_scan = us_banner( tr( "Scan Controls" ) );
193 
194  // Scans
195  QLabel* lb_from = us_label( tr( "Scan Focus from:" ), -1 );
196  lb_from->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
197 
198  ct_from = us_counter( 3, 0.0, 0.0 ); // Update range upon load
199  ct_from->setStep( 1 );
200 
201  QLabel* lb_to = us_label( tr( "to:" ), -1 );
202  lb_to->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
203 
204  ct_to = us_counter( 3, 0.0, 0.0 ); // Update range upon load
205  ct_to->setStep( 1 );
206 
207  // Exclude and Include pushbuttons
208  pb_excludeRange = us_pushbutton( tr( "Exclude Scan Range" ), false );
209  pb_exclusion = us_pushbutton( tr( "Exclusion Profile" ), false );
210  pb_edit1 = us_pushbutton( tr( "Edit Single Scan" ), false );
211  pb_include = us_pushbutton( tr( "Include All" ), false );
212 
213  // Edit controls
214  QLabel* lb_edit = us_banner( tr( "Edit Controls" ) );
215 
216  // Edit Triple:Speed display (Equilibrium only)
217  lb_edtrsp = us_label( tr( "Edit Triple:Speed :" ), -1, true );
218  le_edtrsp = us_lineedit( "" );
219  lb_edtrsp->setVisible( false );
220  le_edtrsp->setVisible( false );
221 
222  // Meniscus
223  pb_meniscus = us_pushbutton( tr( "Specify Meniscus" ), false );
224  le_meniscus = us_lineedit( "", 1 );
225 
226  // Air Gap (hidden by default)
227  pb_airGap = us_pushbutton( tr( "Specify Air Gap" ), false );
228  le_airGap = us_lineedit( "", 1, true );
229  pb_airGap->setHidden( true );
230  le_airGap->setHidden( true );
231 
232  // Data range
233  pb_dataRange = us_pushbutton( tr( "Specify Data Range" ), false );
234  le_dataRange = us_lineedit( "", 1, true );
235  // Plateau
236  pb_plateau = us_pushbutton( tr( "Specify Plateau" ), false );
237  le_plateau = us_lineedit( "", 1, true );
238  // Baseline
239  lb_baseline = us_label( tr( "Baseline:" ), -1 );
240  le_baseline = us_lineedit( "", 1, true );
241 
242  // OD Limit
243  lb_odlim = us_label( tr( "OD Limit:" ), -1 );
244  odlimit = 1.8;
245  ct_odlim = us_counter( 3, 0.1, 50000.0, odlimit );
246  ct_odlim ->setFont( font );
247  ct_odlim ->setStep( 0.01 );
248  ct_odlim ->setMinimumWidth( lwid );
249  ct_odlim ->resize( rhgt, swid );
250 
251  // Noise, Residuals, Invert, Spikes, Prior, Undo
252  pb_noise = us_pushbutton( tr( "Determine RI Noise" ), false );
253  pb_residuals = us_pushbutton( tr( "Subtract Noise" ), false );
254  pb_invert = us_pushbutton( tr( "Invert Sign" ), false );
255  pb_spikes = us_pushbutton( tr( "Remove Spikes" ), false );
256  pb_priorEdits = us_pushbutton( tr( "Apply Prior Edits" ), false );
257  pb_undo = us_pushbutton( tr( "Undo Noise and Spikes" ), false );
258 
259  // Review, Next Triple, Float, Save, Save-all
260  pb_reviewep = us_pushbutton( tr( "Review Edit Profile" ), false );
261  pb_nexttrip = us_pushbutton( tr( "Next Triple" ), false );
262  pb_reviewep->setVisible( false );
263  pb_nexttrip->setVisible( false );
264  pb_float = us_pushbutton( tr( "Mark Data as Floating" ), false );
265  pb_write = us_pushbutton( tr( "Save Current Edit Profile" ), false );
266  lo_writemwl = us_checkbox ( tr( "Save to all Wavelengths" ),
267  ck_writemwl, true );
268 
269  connect( pb_excludeRange, SIGNAL( clicked() ), SLOT( exclude_range() ) );
270  connect( pb_details, SIGNAL( clicked() ), SLOT( details() ) );
271  connect( pb_investigator, SIGNAL( clicked() ),
272  SLOT ( sel_investigator() ) );
273  connect( pb_load, SIGNAL( clicked() ), SLOT( load() ) );
274  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
275  SLOT ( new_triple ( int ) ) );
276  connect( pb_exclusion, SIGNAL( clicked() ), SLOT( exclusion() ) );
277  connect( pb_edit1, SIGNAL( clicked() ), SLOT( edit_scan() ) );
278  connect( pb_include, SIGNAL( clicked() ), SLOT( include() ) );
279  connect( pb_meniscus, SIGNAL( clicked() ), SLOT( set_meniscus() ) );
280  connect( pb_airGap, SIGNAL( clicked() ), SLOT( set_airGap() ) );
281  connect( pb_dataRange, SIGNAL( clicked() ), SLOT( set_dataRange() ) );
282  connect( pb_plateau, SIGNAL( clicked() ), SLOT( set_plateau() ) );
283  connect( ct_odlim, SIGNAL( valueChanged ( double ) ),
284  SLOT ( od_radius_limit( double ) ) );
285  connect( pb_noise, SIGNAL( clicked() ), SLOT( noise() ) );
286  connect( pb_residuals, SIGNAL( clicked() ),
287  SLOT ( subtract_residuals() ) );
288  connect( pb_invert, SIGNAL( clicked() ), SLOT( invert_values() ) );
289  connect( pb_spikes, SIGNAL( clicked() ), SLOT( remove_spikes() ) );
290  connect( pb_priorEdits, SIGNAL( clicked() ), SLOT( apply_prior() ) );
291  connect( pb_undo, SIGNAL( clicked() ), SLOT( undo() ) );
292  connect( pb_reviewep, SIGNAL( clicked() ), SLOT( review_edits() ) );
293  connect( pb_nexttrip, SIGNAL( clicked() ), SLOT( next_triple() ) );
294  connect( pb_float, SIGNAL( clicked() ), SLOT( floating() ) );
295  connect( pb_write, SIGNAL( clicked() ), SLOT( write() ) );
296 
297  // Lay out specs widgets and layouts
298  int s_row = 0;
299  specs->addWidget( pb_investigator, s_row, 0, 1, 1 );
300  specs->addWidget( le_investigator, s_row++, 1, 1, 3 );
301  specs->addLayout( disk_controls, s_row++, 0, 1, 4 );
302  specs->addWidget( pb_load, s_row, 0, 1, 2 );
303  specs->addWidget( pb_details, s_row++, 2, 1, 2 );
304  specs->addWidget( lb_triple, s_row, 0, 1, 2 );
305  specs->addWidget( cb_triple, s_row++, 2, 1, 2 );
306  specs->addWidget( lb_rpms, s_row, 0, 1, 2 );
307  specs->addWidget( cb_rpms, s_row++, 2, 1, 2 );
308  specs->addWidget( lb_gaps, s_row, 0, 1, 2 );
309  specs->addWidget( ct_gaps, s_row++, 2, 1, 2 );
310  specs->addWidget( le_lxrng, s_row++, 0, 1, 4 );
311  specs->addWidget( lb_mwlctl, s_row++, 0, 1, 4 );
312  specs->addLayout( lo_lrange, s_row, 0, 1, 2 );
313  specs->addLayout( lo_custom, s_row++, 2, 1, 2 );
314  specs->addWidget( lb_ldelta, s_row, 0, 1, 1 );
315  specs->addWidget( ct_ldelta, s_row, 1, 1, 1 );
316  specs->addWidget( le_ltrng, s_row++, 2, 1, 2 );
317  specs->addWidget( lb_lstart, s_row, 0, 1, 1 );
318  specs->addWidget( cb_lstart, s_row, 1, 1, 1 );
319  specs->addWidget( lb_lend, s_row, 2, 1, 1 );
320  specs->addWidget( cb_lend, s_row++, 3, 1, 1 );
321  specs->addWidget( pb_custom, s_row, 0, 1, 2 );
322  specs->addWidget( pb_incall, s_row++, 2, 1, 2 );
323  specs->addLayout( lo_radius, s_row, 0, 1, 2 );
324  specs->addLayout( lo_waveln, s_row++, 2, 1, 2 );
325  specs->addWidget( lb_lplot, s_row, 0, 1, 1 );
326  specs->addWidget( cb_lplot, s_row, 1, 1, 1 );
327  specs->addWidget( pb_larrow, s_row, 2, 1, 1 );
328  specs->addWidget( pb_rarrow, s_row++, 3, 1, 1 );
329  specs->addWidget( lb_scan, s_row++, 0, 1, 4 );
330  specs->addWidget( lb_from, s_row, 0, 1, 2 );
331  specs->addWidget( ct_from, s_row++, 2, 1, 2 );
332  specs->addWidget( lb_to, s_row, 0, 1, 2 );
333  specs->addWidget( ct_to, s_row++, 2, 1, 2 );
334  specs->addWidget( pb_excludeRange, s_row, 0, 1, 2 );
335  specs->addWidget( pb_exclusion, s_row++, 2, 1, 2 );
336  specs->addWidget( pb_edit1, s_row, 0, 1, 2 );
337  specs->addWidget( pb_include, s_row++, 2, 1, 2 );
338  specs->addWidget( lb_edit, s_row++, 0, 1, 4 );
339  specs->addWidget( lb_edtrsp, s_row, 0, 1, 2 );
340  specs->addWidget( le_edtrsp, s_row++, 2, 1, 2 );
341  specs->addWidget( pb_meniscus, s_row, 0, 1, 2 );
342  specs->addWidget( le_meniscus, s_row++, 2, 1, 2 );
343  specs->addWidget( pb_airGap, s_row, 0, 1, 2 );
344  specs->addWidget( le_airGap, s_row++, 2, 1, 2 );
345  specs->addWidget( pb_dataRange, s_row, 0, 1, 2 );
346  specs->addWidget( le_dataRange, s_row++, 2, 1, 2 );
347  specs->addWidget( pb_plateau, s_row, 0, 1, 2 );
348  specs->addWidget( le_plateau, s_row++, 2, 1, 2 );
349  specs->addWidget( lb_baseline, s_row, 0, 1, 2 );
350  specs->addWidget( le_baseline, s_row++, 2, 1, 2 );
351  specs->addWidget( lb_odlim, s_row, 0, 1, 2 );
352  specs->addWidget( ct_odlim, s_row++, 2, 1, 2 );
353  specs->addWidget( pb_noise, s_row, 0, 1, 2 );
354  specs->addWidget( pb_residuals, s_row++, 2, 1, 2 );
355  specs->addWidget( pb_invert, s_row, 0, 1, 2 );
356  specs->addWidget( pb_spikes, s_row++, 2, 1, 2 );
357  specs->addWidget( pb_priorEdits, s_row, 0, 1, 2 );
358  specs->addWidget( pb_undo, s_row++, 2, 1, 2 );
359  specs->addWidget( pb_reviewep, s_row, 0, 1, 2 );
360  specs->addWidget( pb_nexttrip, s_row++, 2, 1, 2 );
361  specs->addWidget( pb_float, s_row, 0, 1, 2 );
362  specs->addWidget( pb_write, s_row++, 2, 1, 2 );
363  specs->addLayout( lo_writemwl, s_row++, 2, 1, 2 );
364 
365  // Button rows
366  QBoxLayout* buttons = new QHBoxLayout;
367  QPushButton* pb_reset = us_pushbutton( tr( "Reset" ) );
368  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
369  QPushButton* pb_accept = us_pushbutton( tr( "Close" ) );
370 
371  connect( pb_reset, SIGNAL( clicked() ), SLOT( reset() ) );
372  connect( pb_help, SIGNAL( clicked() ), SLOT( help() ) );
373  connect( pb_accept, SIGNAL( clicked() ), SLOT( close() ) );
374 
375  buttons->addWidget( pb_reset );
376  buttons->addWidget( pb_help );
377  buttons->addWidget( pb_accept );
378 
379  // Plot layout on right side of window
380  plot = new US_Plot( data_plot,
381  tr( "Absorbance Data" ),
382  tr( "Radius (in cm)" ), tr( "Absorbance" ) );
383 
384  data_plot->setMinimumSize( 600, 400 );
385 
386  data_plot->enableAxis( QwtPlot::xBottom, true );
387  data_plot->enableAxis( QwtPlot::yLeft , true );
388 
389  pick = new US_PlotPicker( data_plot );
390  // Set rubber band to display for Control+Left Mouse Button
391  pick->setRubberBand ( QwtPicker::VLineRubberBand );
392  pick->setMousePattern( QwtEventPattern::MouseSelect1,
393  Qt::LeftButton, Qt::ControlModifier );
394 
395  left->addLayout( specs );
396  left->addStretch();
397  left->addLayout( buttons );
398 
399  main->addLayout( left );
400  main->addLayout( plot );
401  main->setStretchFactor( left, 2 );
402  main->setStretchFactor( plot, 3 );
403  top ->addLayout( main );
404 
405  reset();
406 }
407 
408 // Select DB investigator
410 {
411  int investigator = US_Settings::us_inv_ID();
412 
413  US_Investigator* dialog = new US_Investigator( true, investigator );
414  dialog->exec();
415 
416  investigator = US_Settings::us_inv_ID();
417 
418  QString inv_text = QString::number( investigator ) + ": "
420 
421  le_investigator->setText( inv_text );
422 }
423 
424 // Reset parameters to their defaults
425 void US_Edit::reset( void )
426 {
427  changes_made = false;
428  floatingData = false;
429 
430  step = MENISCUS;
431  meniscus = 0.0;
432  meniscus_left = 0.0;
433  airGap_left = 0.0;
434  airGap_right = 9.0;
435  range_left = 0.0;
436  range_right = 9.0;
437  plateau = 0.0;
438  baseline = 0.0;
439  invert = 1.0; // Multiplier = 1.0 or -1.0
440  noise_order = 0;
441  triple_index = 0;
442  data_index = 0;
443  isMwl = false;
444  xaxis_radius = true;
445  lsel_range = true;
446 
447  le_info ->setText( "" );
448  le_meniscus ->setText( "" );
449  le_airGap ->setText( "" );
450  le_dataRange->setText( "" );
451  le_plateau ->setText( "" );
452  le_baseline ->setText( "" );
453 
454  lb_gaps->setText( tr( "Threshold for Scan Gaps" ) );
455  ct_gaps->setValue( 50.0 );
456 
457  ct_from->disconnect();
458  ct_from->setMinValue( 0 );
459  ct_from->setMaxValue( 0 );
460  ct_from->setValue ( 0 );
461 
462  ct_to->disconnect();
463  ct_to->setMinValue( 0 );
464  ct_to->setMaxValue( 0 );
465  ct_to->setValue ( 0 );
466 
467  cb_triple->disconnect();
468 
469  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
470  data_plot->detachItems( QwtPlotItem::Rtti_PlotMarker );
471  v_line = NULL;
472  pick ->disconnect();
473 
474  data_plot->setAxisScale( QwtPlot::xBottom, 5.7, 7.3 );
475  data_plot->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
476  grid = us_grid( data_plot );
477  data_plot->replot();
478 
479  // Disable pushbuttons
480  pb_details ->setEnabled( false );
481 
482  pb_excludeRange->setEnabled( false );
483  pb_exclusion ->setEnabled( false );
484  pb_include ->setEnabled( false );
485  pb_edit1 ->setEnabled( false );
486 
487  pb_meniscus ->setEnabled( false );
488  pb_airGap ->setEnabled( false );
489  pb_dataRange ->setEnabled( false );
490  pb_plateau ->setEnabled( false );
491 
492  pb_noise ->setEnabled( false );
493  pb_residuals ->setEnabled( false );
494  pb_spikes ->setEnabled( false );
495  pb_invert ->setEnabled( false );
496  pb_priorEdits ->setEnabled( false );
497  pb_reviewep ->setEnabled( false );
498  pb_nexttrip ->setEnabled( false );
499  pb_undo ->setEnabled( false );
500 
501  pb_float ->setEnabled( false );
502  pb_write ->setEnabled( false );
503  ck_writemwl ->setEnabled( false );
504 
505  // Remove icons
506  pb_meniscus ->setIcon( QIcon() );
507  pb_airGap ->setIcon( QIcon() );
508  pb_dataRange ->setIcon( QIcon() );
509  pb_plateau ->setIcon( QIcon() );
510  pb_noise ->setIcon( QIcon() );
511  pb_residuals ->setIcon( QIcon() );
512  pb_spikes ->setIcon( QIcon() );
513  pb_invert ->setIcon( QIcon() );
514 
515  pb_float ->setIcon( QIcon() );
516 
517  editLabel .clear();
518  data.scanData .clear();
519  includes .clear();
520  changed_points.clear();
521  trip_rpms .clear();
522  triples .clear();
523  cb_triple ->clear();
524  cb_rpms ->disconnect();
525  cb_rpms ->clear();
526  editGUIDs .clear();
527  editIDs .clear();
528  editFnames .clear();
529  files .clear();
530  expd_radii .clear();
531  expi_wvlns .clear();
532  rawi_wvlns .clear();
533  celchns .clear();
534  rawc_wvlns .clear();
535  expc_wvlns .clear();
536  expc_radii .clear();
537  connect_mwl_ctrls( false );
538  rb_lrange ->setChecked( true );
539  rb_custom ->setChecked( false );
540  cb_lplot ->clear();
541  cb_lstart ->clear();
542  cb_lend ->clear();
543  ct_ldelta ->setEnabled( true );
544  cb_lend ->setEnabled( true );
545  rb_radius ->setChecked( true );
546  rb_waveln ->setChecked( false );
547  pb_custom ->setEnabled( false );
548  connect_mwl_ctrls( true );
549 
550  set_pbColors( NULL );
551  lb_triple->setText( tr( "Cell / Channel / Wavelength" ) );
552 
553  show_mwl_controls( false );
554 }
555 
556 // Reset parameters for a new triple
558 {
559  step = MENISCUS;
560  meniscus = 0.0;
561  meniscus_left = 0.0;
562  airGap_left = 0.0;
563  airGap_right = 9.0;
564  range_left = 0.0;
565  range_right = 9.0;
566  plateau = 0.0;
567  baseline = 0.0;
568  invert = 1.0; // Multiplier = 1.0 or -1.0
569  noise_order = 0;
570 
571  le_info ->setText( "" );
572  le_meniscus ->setText( "" );
573  le_airGap ->setText( "" );
574  le_dataRange->setText( "" );
575  le_plateau ->setText( "" );
576  le_baseline ->setText( "" );
577 
578  if ( dataType == "IP" )
579  ct_gaps->setValue( 0.4 );
580  else
581  ct_gaps->setValue( 50.0 );
582 
583  ct_from->disconnect();
584  ct_from->setMinValue( 0 );
585  ct_from->setMaxValue( 0 );
586  ct_from->setValue ( 0 );
587 
588  ct_to->disconnect();
589  ct_to->setMinValue( 0 );
590  ct_to->setMaxValue( 0 );
591  ct_to->setValue ( 0 );
592 
593  data.scanData .clear();
594  includes .clear();
595  changed_points.clear();
596  trip_rpms .clear();
597 
598  cb_triple ->disconnect();
599  cb_rpms ->disconnect();
600  cb_rpms ->clear();
601 }
602 
603 // Display run details
604 void US_Edit::details( void )
605 {
606  US_RunDetails2* dialog
608  dialog->exec();
609  qApp->processEvents();
610  delete dialog;
611 }
612 
613 // Do a Gap check against threshold value
614 void US_Edit::gap_check( void )
615 {
616  int threshold = (int)ct_gaps->value();
617 
618  US_DataIO::Scan s;
619  QString gaps;
620 
621  int scanNumber = 0;
622  int rawScanNumber = -1;
623  bool deleteAll = false;
624 
625  foreach ( s, data.scanData )
626  {
627  rawScanNumber++;
628  // If scan has been deleted, skip to next
629  if ( ! includes.contains( scanNumber ) ) continue;
630 
631  int maxGap = 0;
632  int gapLength = 0;
633  int location = 0;
634 
635  int leftPoint = data.xindex( range_left );
636  int rightPoint = data.xindex( range_right );
637 
638  for ( int i = leftPoint; i <= rightPoint; i++ )
639  {
640  int byte = i / 8;
641  int bit = i % 8;
642 
643  if ( s.interpolated[ byte ] & 1 << ( 7 - bit ) )
644  gapLength++;
645  else
646  gapLength = 0;
647 
648  if ( gapLength > maxGap )
649  {
650  maxGap = gapLength;
651  location = i;
652  }
653  }
654 
655  if ( maxGap >= threshold )
656  {
657  QwtPlotCurve* curve = NULL;
658  bool deleteCurrent = false;
659 
660  // Hightlight scan
661  ct_to->setValue( 0.0 ); // Unfocus everything
662 
663  QString seconds = QString::number( s.seconds );
664  QwtPlotItemList items = data_plot->itemList();
665 
666  for ( int i = 0; i < items.size(); i++ )
667  {
668  if ( items[ i ]->rtti() == QwtPlotItem::Rtti_PlotCurve )
669  {
670  if ( items[ i ]->title().text().contains( seconds ) )
671  {
672  curve = dynamic_cast< QwtPlotCurve* >( items[ i ] );
673  break;
674  }
675  }
676  }
677 
678  if ( curve == NULL )
679  {
680  qDebug() << "Cannot find curve during gap check";
681  return;
682  }
683 
684  // Popup unless delete all is set
685  if ( ! deleteAll )
686  {
687  // Color the selected point
688  QPen p = curve->pen();
689  QBrush b = curve->brush();
690 
691  p.setColor( Qt::red );
692  b.setColor( Qt::red );
693 
694  curve->setPen ( p );
695  curve->setBrush( b );
696  data_plot->replot();
697 
698  // Ask the user what to do
699  QMessageBox box;
700 
701  box.setWindowTitle( tr( "Excessive Scan Gaps Detected" ) );
702 
703  double radius = data.xvalues[ 0 ] + location * s.delta_r;
704 
705  gaps = tr( "Scan " )
706  + QString::number( rawScanNumber )
707  + tr( " has a maximum reading gap of " )
708  + QString::number( maxGap )
709  + tr( " starting at radius " )
710  + QString::number( radius, 'f', 3 );
711 
712  box.setText( gaps );
713  box.setInformativeText( tr( "Delete?" ) );
714 
715  QPushButton* pb_delete = box.addButton( tr( "Delete" ),
716  QMessageBox::YesRole );
717 
718  QPushButton* pb_deleteAll = box.addButton( tr( "Delete All" ),
719  QMessageBox::AcceptRole );
720 
721  QPushButton* pb_skip = box.addButton( tr( "Skip" ),
722  QMessageBox::NoRole );
723 
724  QPushButton* pb_cancel = box.addButton( tr( "Cancel" ),
725  QMessageBox::RejectRole );
726 
727  box.setEscapeButton ( pb_cancel );
728  box.setDefaultButton( pb_delete );
729 
730  box.exec();
731 
732  if ( box.clickedButton() == pb_delete )
733  deleteCurrent = true;
734 
735  else if ( box.clickedButton() == pb_deleteAll )
736  {
737  deleteAll = true;
738  deleteCurrent = true;
739  }
740 
741  else
742  {
743  // Uncolor scan
744  p.setColor( Qt::yellow );
745  b.setColor( Qt::yellow );
746 
747  curve->setPen ( p );
748  curve->setBrush( b );
749  data_plot->replot();
750  }
751 
752  if ( box.clickedButton() == pb_skip )
753  continue;
754 
755  if ( box.clickedButton() == pb_cancel )
756  return;
757  }
758 
759  // Delete the scan
760  if ( deleteAll || deleteCurrent )
761  {
762  includes.removeOne( scanNumber );
763  replot();
764 
765  ct_to ->setMaxValue( includes.size() );
766  ct_from->setMaxValue( includes.size() );
767  }
768  }
769 
770  scanNumber++;
771  }
772 }
773 
774 // Load an AUC data set
775 void US_Edit::load( void )
776 {
777  bool isLocal = ! disk_controls->db();
778  reset();
779 
780  US_LoadAUC* dialog =
781  new US_LoadAUC( isLocal, allData, triples, workingDir );
782 
783  connect( dialog, SIGNAL( progress ( QString ) ),
784  this, SLOT ( progress_load ( QString ) ) );
785  connect( dialog, SIGNAL( changed ( bool ) ),
786  this, SLOT ( update_disk_db( bool ) ) );
787 
788  if ( dialog->exec() == QDialog::Rejected ) return;
789 
790  runID = workingDir.section( "/", -1, -1 );
791 DbgLv(1) << "Ld: runID" << runID << "wdir" << workingDir;
792  sData .clear();
793  sd_offs .clear();
794  sd_knts .clear();
795  cb_triple->clear();
796  files .clear();
797  delete dialog;
798 
799  if ( triples.size() == 0 )
800  {
801  QMessageBox::warning( this,
802  tr( "No Files Found" ),
803  tr( "There were no files of the form *.auc\n"
804  "found in the specified directory." ) );
805  return;
806  }
807 
808  cb_triple->addItems( triples );
809  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
810  SLOT ( new_triple ( int ) ) );
811  triple_index = 0;
812  data_index = 0;
813 
814  le_info->setText( runID );
815 
816  data = allData[ 0 ];
817  dataType = QString( QChar( data.type[ 0 ] ) )
818  + QString( QChar( data.type[ 1 ] ) );
819 
820  if ( dataType == "IP" )
821  {
822  lb_gaps->setText( tr( "Fringe Tolerance" ) );
823 
824  ct_gaps->setRange ( 0.0, 20.0, 0.001 );
825  ct_gaps->setValue ( 0.4 );
826  ct_gaps->setNumButtons( 3 );
827 
828  connect( ct_gaps, SIGNAL( valueChanged ( double ) ),
829  SLOT ( set_fringe_tolerance( double ) ) );
830  }
831  else
832  {
833  lb_gaps->setText( tr( "Threshold for Scan Gaps" ) );
834 
835  ct_gaps->disconnect ();
836  ct_gaps->setRange ( 10.0, 100.0, 10.0 );
837  ct_gaps->setValue ( 50.0 );
838  ct_gaps->setNumButtons( 1 );
839  }
840 
841  QString runtype = runID + "." + dataType;
842 DbgLv(1) << "Ld: runtype" << runtype;
843  nwaveln = 0;
844  ncelchn = 0;
845  outData.clear();
846 
847  for ( int trx = 0; trx < triples.size(); trx++ )
848  { // Generate file names
849  QString triple = QString( triples.at( trx ) ).replace( " / ", "." );
850  QString file = runtype + "." + triple + ".auc";
851  files << file;
852 
853  // Save pointers as initial output data vector
854  outData << &allData[ trx ];
855 
856  QString scell = triple.section( ".", 0, 0 ).simplified();
857  QString schan = triple.section( ".", 1, 1 ).simplified();
858  QString swavl = triple.section( ".", 2, 2 ).simplified();
859 
860  if ( ! rawc_wvlns.contains( swavl ) )
861  { // Accumulate wavelengths in case this is MWL
862  nwaveln++;
863  rawc_wvlns << swavl;
864  }
865 
866  nwavelo = nwaveln;
867  QString celchn = scell + " / " + schan;
868 
869  if ( ! celchns.contains( celchn ) )
870  { // Accumulate cell/channel values in case this is MWL
871  ncelchn++;
872  celchns << celchn;
873  }
874  }
875 DbgLv(1) << "rawc_wvlns size" << rawc_wvlns.size() << nwaveln;
876 DbgLv(1) << " celchns size" << celchns.size() << ncelchn;
877  rawc_wvlns.sort();
878  rawi_wvlns.clear();
879  toti_wvlns.clear();
880 
881  for ( int wvx = 0; wvx < nwaveln; wvx++ )
882  {
883  int iwavl = rawc_wvlns[ wvx ].toInt();
884  rawi_wvlns << iwavl;
885  toti_wvlns << iwavl;
886  }
887 
888  workingDir = workingDir + "/";
889  QString file = workingDir + runtype + ".xml";
890  expType = "";
891  QFile xf( file );
892 
893  if ( xf.open( QIODevice::ReadOnly | QIODevice::Text ) )
894  {
895  QXmlStreamReader xml( &xf );
896 
897  while( ! xml.atEnd() )
898  {
899  xml.readNext();
900 
901  if ( xml.isStartElement() && xml.name() == "experiment" )
902  {
903  QXmlStreamAttributes xa = xml.attributes();
904  expType = xa.value( "type" ).toString();
905  break;
906  }
907  }
908 
909  xf.close();
910  }
911 
912  if ( expType.isEmpty() && disk_controls->db() )
913  { // no experiment type yet and data read from DB: try for DB exp type
914  if ( dbP == NULL )
915  {
916  US_Passwd pw;
917  dbP = new US_DB2( pw.getPasswd() );
918 
919  if ( dbP == NULL || dbP->lastErrno() != US_DB2::OK )
920  {
921  QMessageBox::warning( this, tr( "Connection Problem" ),
922  tr( "Could not connect to database\n" )
923  + ( ( dbP != NULL ) ? dbP->lastError() : "" ) );
924  dbP = NULL;
925  return;
926  }
927  }
928 
929  QStringList query;
930  query << "get_experiment_info_by_runID" << runID
931  << QString::number( US_Settings::us_inv_ID() );
932 
933  dbP->query( query );
934  dbP->next();
935  expType = dbP->value( 8 ).toString();
936  }
937 
938  if ( expType.isEmpty() ) // if no experiment type, assume Velocity
939  expType = "Velocity";
940 
941  else // insure Ulll... form, e.g., "Equilibrium"
942  expType = expType.left( 1 ).toUpper() +
943  expType.mid( 1 ).toLower();
944 
945 
946  // Set booleans for experiment type
947  expIsVelo = ( expType.compare( "Velocity", Qt::CaseInsensitive ) == 0 );
948  expIsEquil = ( expType.compare( "Equilibrium", Qt::CaseInsensitive ) == 0 );
949  expIsDiff = ( expType.compare( "Diffusion", Qt::CaseInsensitive ) == 0 );
950  expIsOther = ( !expIsVelo && !expIsEquil && !expIsDiff );
951  expType = expIsOther ? "Other" : expType;
952  odlimit = 1.8;
953  init_includes();
954 
955  if ( expIsEquil )
956  { // Equilibrium
957  lb_rpms ->setVisible( true );
958  cb_rpms ->setVisible( true );
959  pb_plateau ->setVisible( false );
960  le_plateau ->setVisible( false );
961  lb_baseline->setVisible( false );
962  le_baseline->setVisible( false );
963  lb_edtrsp ->setVisible( true );
964  le_edtrsp ->setVisible( true );
965  pb_reviewep->setVisible( true );
966  pb_nexttrip->setVisible( true );
967  pb_write ->setText( tr( "Save Edit Profiles" ) );
968 
969  sData.clear();
970  US_DataIO::SpeedData ssDat;
971  int ksd = 0;
972 
973  for ( int jd = 0; jd < allData.size(); jd++ )
974  {
975  data = allData[ jd ];
976  sd_offs << ksd;
977 
978  if ( jd > 0 )
979  sd_knts << ( ksd - sd_offs[ jd - 1 ] );
980 
981  trip_rpms.clear();
982 
983  for ( int ii = 0; ii < data.scanData.size(); ii++ )
984  {
985  double drpm = data.scanData[ ii ].rpm;
986  QString arpm = QString::number( drpm );
987  if ( ! trip_rpms.contains( arpm ) )
988  {
989  trip_rpms << arpm;
990  ssDat.first_scan = ii + 1;
991  ssDat.scan_count = 1;
992  ssDat.speed = drpm;
993  ssDat.meniscus = 0.0;
994  ssDat.dataLeft = 0.0;
995  ssDat.dataRight = 0.0;
996  sData << ssDat;
997  ksd++;
998  }
999 
1000  else
1001  {
1002  int jj = trip_rpms.indexOf( arpm );
1003  ssDat = sData[ jj ];
1004  ssDat.scan_count++;
1005  sData[ jj ].scan_count++;
1006  }
1007  }
1008 
1009  if ( jd == 0 )
1010  cb_rpms->addItems( trip_rpms );
1011 
1012  total_speeds += trip_rpms.size();
1013  }
1014 
1015  sd_knts << ( ksd - sd_offs[ allData.size() - 1 ] );
1016 
1017  if ( allData.size() > 1 )
1018  {
1019  data = allData[ 0 ];
1020  ksd = sd_knts[ 0 ];
1021  trip_rpms.clear();
1022  cb_rpms ->clear();
1023  for ( int ii = 0; ii < ksd; ii++ )
1024  {
1025  QString arpm = QString::number( sData[ ii ].speed );
1026  trip_rpms << arpm;
1027  }
1028 
1029  cb_rpms->addItems( trip_rpms );
1030  }
1031 
1032  pick ->disconnect();
1033  connect( pick, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
1034  SLOT ( mouse ( const QwtDoublePoint& ) ) );
1035 
1036  pb_priorEdits->disconnect();
1037  connect( pb_priorEdits, SIGNAL( clicked() ), SLOT( prior_equil() ) );
1038  plot_scan();
1039 
1040  connect( cb_rpms, SIGNAL( currentIndexChanged( int ) ),
1041  SLOT ( new_rpmval ( int ) ) );
1042  }
1043 
1044  else
1045  { // non-Equilibrium
1046  bool notMwl = ( nwaveln < 3 );
1047  lb_rpms ->setVisible( false );
1048  cb_rpms ->setVisible( false );
1049  pb_plateau ->setVisible( true );
1050  le_plateau ->setVisible( true );
1051  lb_baseline->setVisible( notMwl );
1052  le_baseline->setVisible( notMwl );
1053  lb_edtrsp ->setVisible( false );
1054  le_edtrsp ->setVisible( false );
1055  pb_reviewep->setVisible( false );
1056  pb_nexttrip->setVisible( false );
1057 
1058  pb_write ->setText( tr( "Save Current Edit Profile" ) );
1059 
1060  pb_priorEdits->disconnect();
1061  connect( pb_priorEdits, SIGNAL( clicked() ), SLOT( apply_prior() ) );
1062 DbgLv(1) << "LD(): triples size" << triples.size();
1063  if ( notMwl )
1064  plot_current( 0 );
1065  }
1066 
1067  // Enable pushbuttons
1068  pb_details ->setEnabled( true );
1069  pb_include ->setEnabled( true );
1070  pb_exclusion ->setEnabled( true );
1071  pb_meniscus ->setEnabled( true );
1072  pb_airGap ->setEnabled( false );
1073  pb_dataRange ->setEnabled( false );
1074  pb_plateau ->setEnabled( false );
1075  pb_noise ->setEnabled( false );
1076  pb_spikes ->setEnabled( false );
1077  pb_invert ->setEnabled( true );
1078  pb_priorEdits->setEnabled( true );
1079  pb_float ->setEnabled( true );
1080  pb_undo ->setEnabled( true );
1081 
1082  connect( ct_from, SIGNAL( valueChanged ( double ) ),
1083  SLOT ( focus_from ( double ) ) );
1084 
1085  connect( ct_to, SIGNAL( valueChanged ( double ) ),
1086  SLOT ( focus_to ( double ) ) );
1087 
1088  step = MENISCUS;
1090 
1091  // Temperature check
1092  double dt = 0.0;
1093  US_DataIO::RawData triple;
1094 
1095  foreach( triple, allData )
1096  {
1097  double temp_spread = triple.temperature_spread();
1098  dt = ( temp_spread > dt ) ? temp_spread : dt;
1099  }
1100 
1101  if ( dt > US_Settings::tempTolerance() )
1102  {
1103  QMessageBox::warning( this,
1104  tr( "Temperature Problem" ),
1105  tr( "The temperature in this run varied over the course\n"
1106  "of the run to a larger extent than allowed by the\n"
1107  "current threshold (" )
1108  + QString::number( US_Settings::tempTolerance(), 'f', 1 )
1109  + " " + DEGC + tr( ". The accuracy of experimental\n"
1110  "results may be affected significantly." ) );
1111  }
1112 
1113  ntriple = triples.size();
1114 DbgLv(1) << " triples size" << ntriple;
1115  editGUIDs .fill( "", ntriple );
1116  editIDs .fill( "", ntriple );
1117  editFnames.fill( "none", ntriple );
1118 
1119  isMwl = ( nwaveln > 2 && ntriple > 8 );
1120  lrng_bycell = false; // Assume initially cell lambdas all the same
1121 DbgLv(1) << "LD(): isMwl" << isMwl << "nwaveln" << nwaveln << toti_wvlns.size();
1122 
1123  if ( isMwl )
1124  { // Set values related to MultiWaveLength
1125  connect_mwl_ctrls( false );
1126 
1127  // Load the internal object that keeps track of MWL data
1128 DbgLv(1) << "IS-MWL: load_mwl begun";
1130 DbgLv(1) << "IS-MWL: load_mwl complete";
1131 
1132  // Initial export lambdas are input lambdas: save the input lists
1133  ncelchn = mwl_data.countOf( "cellchann" );
1134  maxwavl = rawc_wvlns.size();
1135 DbgLv(1) << "IS-MWL: max wvlns size" << maxwavl;
1136  wavelns_i.clear();
1137 
1138  for ( int ccx = 0; ccx < ncelchn; ccx++ )
1139  { // Save lambdas for each cell; flag if any cell-to-cell differences
1140  QVector< int > wvs;
1141  nwavelo = mwl_data.lambdas( wvs, ccx );
1142  wavelns_i << wvs;
1143 
1144  if ( nwavelo != maxwavl )
1145  {
1146  lrng_bycell = true; // Flag based on count difference
1147  }
1148 
1149  else
1150  {
1151  for ( int wvx = 0; wvx < nwaveln; wvx++ )
1152  {
1153  if ( wvs[ wvx ] != toti_wvlns[ wvx ] )
1154  {
1155  lrng_bycell = true; // Flag based on value difference
1156  break;
1157  }
1158  }
1159  }
1160  } // END: cell scan loop
1161 
1162  lambdas_by_cell( 0 );
1163 
1164  nwavelo = nwaveln;
1165  slambda = toti_wvlns[ 0 ];
1166  elambda = toti_wvlns[ nwaveln - 1 ];
1167  dlambda = 1;
1168  le_ltrng ->setText( tr( "%1 raw: %2 %3 to %4" )
1169  .arg( nwaveln ).arg( chlamb ).arg( slambda ).arg( elambda ) );
1170  le_lxrng ->setText( tr( "%1 MWL exports: %2 %3 to %4,"
1171  " raw index increment %5" )
1172  .arg( nwavelo ).arg( chlamb ).arg( slambda ).arg( elambda )
1173  .arg( dlambda ) );
1174 
1175  expd_radii .clear();
1176  expc_wvlns .clear();
1178 DbgLv(1) << "IS-MWL: new nwavelo" << nwavelo << expi_wvlns.count();
1179 
1180  // Initialize export wavelength lists for first channel
1181  for ( int wvx = 0; wvx < nwavelo; wvx++ )
1182  {
1183  expc_wvlns << QString::number( expi_wvlns[ wvx ] );
1184  }
1185 
1186  // Update wavelength lists in GUI elements
1187  cb_lstart->clear();
1188  cb_lend ->clear();
1189  cb_lplot ->clear();
1190  cb_lstart->addItems( expc_wvlns );
1191  cb_lend ->addItems( expc_wvlns );
1192  cb_lplot ->addItems( expc_wvlns );
1193  int lastx = nwavelo - 1;
1194  plotndx = nwavelo / 2;
1195  cb_lplot ->setCurrentIndex( plotndx );
1196  cb_lstart->setCurrentIndex( 0 );
1197  cb_lend ->setCurrentIndex( lastx );
1198 DbgLv(1) << "IS-MWL: expi_wvlns size" << expi_wvlns.size() << nwaveln;
1199 
1200  edata = &allData[ 0 ];
1201  nrpoint = edata->pointCount();
1202  int nscan = edata->scanCount();
1203  int ndset = ncelchn * nrpoint;
1204  int ndpoint = nscan * maxwavl;
1205 DbgLv(1) << "IS-MWL: nrpoint nscan ndset ndpoint" << nrpoint << nscan
1206  << ndset << ndpoint;
1207 
1208  for ( int ii = 0; ii < nrpoint; ii++ )
1209  { // Update the list of radii that may be plotted
1210  expd_radii << data.xvalues[ ii ];
1211  expc_radii << QString().sprintf( "%.3f", data.xvalues[ ii ] );
1212  }
1213 DbgLv(1) << "IS-MWL: expd_radii size" << expd_radii.size() << nrpoint;
1214 
1215  QVector< double > wrdata;
1216  wrdata.fill( 0.0, ndpoint );
1217  rdata .clear();
1218 DbgLv(1) << "IS-MWL: wrdata size" << wrdata.size() << ndpoint;
1219 
1220  for ( int ii = 0; ii < ndset; ii++ )
1221  { // Initialize the data vector that has wavelength as the x-axis
1222  rdata << wrdata;
1223  }
1224 DbgLv(1) << "IS-MWL: rdata size" << rdata.size() << ndset;
1225 
1226  // Update wavelength-x-axis data vector with amplitude data points
1227  // The input has (ncelchn * nwaveln) data sets, each of which
1228  // contains (nscan * nrpoint) data points.
1229  // The output has (ncelchn * nrpoint) data sets, each of which
1230  // contains (nscan * nwaveln) data points.
1231  int trx = 0;
1232 
1233  for ( int ccx = 0; ccx < ncelchn; ccx++ )
1234  { // Handle each triple of AUC data
1235  lambdas_by_cell( ccx ); // Lambdas in cell
1236 
1237  for ( int jwx = 0; jwx < nwaveln; jwx++ )
1238  { // Each wavelength in the current cell
1239  edata = &allData[ trx ]; // Triple data
1240  int iwavl = rawi_wvlns[ jwx ]; // Wavelength value
1241  int wvx = toti_wvlns.indexOf( iwavl ); // Wavelength index
1242 DbgLv(1) << "IS-MWL: trx ccx wvx" << trx << ccx << wvx;
1243 
1244  for ( int scx = 0; scx < nscan; scx++ )
1245  { // Each scan of a triple
1246  US_DataIO::Scan* scan = &edata->scanData[ scx ];
1247  int odx = ccx * nrpoint; // Output dataset index
1248  int opx = scx * maxwavl + wvx; // Output point index
1249 DbgLv(2) << "IS-MWL: scx odx opx" << scx << odx << opx;
1250  for ( int rax = 0; rax < nrpoint; rax++ )
1251  { // Store ea. radius data point as a wavelength point in a scan
1252  rdata[ odx++ ][ opx ] = scan->rvalues[ rax ];
1253  } // END: radius points loop
1254  } // END: scans loop
1255 
1256  trx++;
1257  } // END: input triples loop
1258  } // END: input celchn loop
1259 DbgLv(1) << "IS-MWL: Triples loop complete";
1260 
1261 DbgLv(1) << "IS-MWL: celchns size" << celchns.size();
1262  lb_triple->setText( tr( "Cell / Channel" ) );
1263  cb_triple->disconnect();
1264  cb_triple->clear();
1265  cb_triple->addItems( celchns );
1266  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
1267  SLOT ( new_triple ( int ) ) );
1268 
1269  odlimit = 1.8;
1270 
1271  connect_mwl_ctrls( true );
1272 
1273  plot_mwl();
1274  } // END: isMwl=true
1275 //*DEBUG* Print times,omega^ts
1276 else
1277 {
1278  triple = allData[0];
1279  double timel = triple.scanData[0].rpm / 400.0;
1280  double rpmc = 400.0;
1281  int nstep = (int)timel;
1282  double w2ti = 0.0;
1283  for ( int ii=0; ii<nstep; ii++ )
1284  {
1285  w2ti += sq( rpmc * M_PI / 30.0 );
1286  rpmc += 400.0;
1287  }
1288  for ( int ii=0; ii<triple.scanData.size(); ii++ )
1289  {
1290  US_DataIO::Scan* ds=&triple.scanData[ii];
1291  double timec = ds->seconds;
1292  double rpmc = ds->rpm;
1293  w2ti += ( timec - timel ) * sq( rpmc * M_PI / 30.0 );
1294  qDebug() << "scan" << ii+1 << "delta-r rpm seconds" << ds->delta_r
1295  << rpmc << timec << "omega2t w2t-integ" << ds->omega2t << w2ti;
1296  if(ii==0)
1297  {
1298  double deltt = ds->omega2t / sq(rpmc*M_PI/30.0);
1299  double time1 = timel + deltt;
1300  qDebug() << " scan 1 omega2t-implied time" << time1;
1301  }
1302  timel = timec;
1303  }
1304 }
1305 //*DEBUG* Print times,omega^ts
1306 
1307  ct_odlim->disconnect();
1308  ct_odlim->setValue( odlimit );
1309  connect( ct_odlim, SIGNAL( valueChanged ( double ) ),
1310  this, SLOT ( od_radius_limit ( double ) ) );
1311 
1313 }
1314 
1315 // Set pushbutton colors
1316 void US_Edit::set_pbColors( QPushButton* pb )
1317 {
1318  QPalette p = US_GuiSettings::pushbColor();
1319 
1320  pb_meniscus ->setPalette( p );
1321  pb_airGap ->setPalette( p );
1322  pb_dataRange->setPalette( p );
1323  pb_plateau ->setPalette( p );
1324 
1325  if ( pb != NULL )
1326  {
1327  p.setColor( QPalette::Button, Qt::green );
1328  pb->setPalette( p );
1329  }
1330 }
1331 
1332 // Plot the current data set
1333 void US_Edit::plot_current( int index )
1334 {
1335  if ( isMwl )
1336  {
1337  plot_mwl();
1338  return;
1339  }
1340 
1341  // Read the data
1342  QString triple = triples.at( index );
1343  QStringList parts = triple.split( " / " );
1344 
1345  QString cell = parts[ 0 ];
1346  QString channel = parts[ 1 ];
1347  QString wl = parts[ 2 ];
1348 
1349  QString desc = data.description;
1350 
1351  dataType = QString( QChar( data.type[ 0 ] ) )
1352  + QString( QChar( data.type[ 1 ] ) );
1353 
1354  if ( dataType == "IP" )
1355  {
1356  QStringList sl = desc.split( "," );
1357  sl.removeFirst();
1358  desc = sl.join( "," ).trimmed();
1359  }
1360 
1361  le_info->setText( runID + " (" + desc + ")" );
1362 
1363  // Plot Title
1364  QString title23 = tr( "Run ID: %1\n"
1365  "Cell: %2 Channel: %3 Wavelength: %4" )
1366  .arg( runID ).arg( cell ).arg( channel ).arg( wl );
1367  QString title;
1368 
1369  if ( dataType == "RA" )
1370  {
1371  title = "Radial Absorbance Data\n" + title23;
1372  }
1373  else if ( dataType == "RI" )
1374  {
1375  title = "Radial Intensity Data\n" + title23;
1376  data_plot->setAxisTitle( QwtPlot::yLeft, tr( "Intensity " ) );
1377  }
1378  else if ( dataType == "IP" )
1379  {
1380 
1381  title = "Radial Interference Data\n" + title23;
1382  data_plot->setAxisTitle( QwtPlot::yLeft, tr( "Fringes " ) );
1383 
1384  // Enable Air Gap
1385  pb_airGap->setHidden( false );
1386  le_airGap->setHidden( false );
1387  }
1388  else if ( dataType == "FI" )
1389  {
1390  title = "Fluorescence Intensity Data\n" + title23;
1391  data_plot->setAxisTitle( QwtPlot::yLeft, tr( "Fluorescence Intensity " ) );
1392  }
1393  else
1394  title = "File type not recognized";
1395 
1396  data_plot->setTitle( title );
1397 
1398  // Initialize include list
1399  init_includes();
1400 
1401  // Plot current data for cell / channel / wavelength triple
1402  plot_all();
1403 
1404  // Set the Scan spin boxes
1405  ct_from->setMinValue( 0.0 );
1406  ct_from->setMaxValue( data.scanData.size() );
1407 
1408  ct_to ->setMinValue( 0.0 );
1409  ct_to ->setMaxValue( data.scanData.size() );
1410 
1411  pick ->disconnect();
1412  connect( pick, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
1413  SLOT ( mouse ( const QwtDoublePoint& ) ) );
1414 }
1415 
1416 // Re-plot
1417 void US_Edit::replot( void )
1418 {
1419  switch( step )
1420  {
1421  case FINISHED:
1422  case PLATEAU:
1423  plot_range();
1424  break;
1425 
1426  case BASELINE:
1427  plot_last();
1428  break;
1429 
1430  default: // MENISCUS, AIRGAP, RANGE
1431  plot_all();
1432  break;
1433  }
1434 }
1435 
1436 // Handle a mouse click according to the current pick step
1437 void US_Edit::mouse( const QwtDoublePoint& p )
1438 {
1439  double maximum = -1.0e99;
1440 
1441  switch ( step )
1442  {
1443  case MENISCUS:
1444  if ( dataType == "IP" )
1445  {
1446  meniscus = p.x();
1447  // Un-zoom
1448  if ( plot->btnZoom->isChecked() )
1449  plot->btnZoom->setChecked( false );
1450 
1451  draw_vline( meniscus );
1452  }
1453 
1454  else if ( expIsEquil || men_1click )
1455  { // Equilibrium
1456  meniscus_left = p.x();
1457  int ii = data.xindex( meniscus_left );
1459  meniscus = data.radius( ii );
1460  le_meniscus->setText( QString::number( meniscus, 'f', 3 ) );
1461 
1462  data_plot->replot();
1463 
1464  pb_meniscus->setIcon( check );
1465 
1466  pb_dataRange->setEnabled( true );
1467 
1468  next_step();
1469  break;
1470  }
1471 
1472  else if ( meniscus_left == 0.0 )
1473  {
1474  meniscus_left = p.x();
1476  break;
1477  }
1478  else
1479  {
1480  // Sometime we get two clicks
1481  if ( qAbs( p.x() - meniscus_left ) < 0.005 ) return;
1482 
1483  double meniscus_right = p.x();
1484 
1485  // Swap values if necessary. Use a macro in us_math.h
1486  if ( meniscus_right < meniscus_left )
1487  swap_double( meniscus_left, meniscus_right );
1488 
1489  // Find the radius for the max value
1490  maximum = -1.0e99;
1491  US_DataIO::Scan* s;
1492 
1493  for ( int i = 0; i < data.scanData.size(); i++ )
1494  {
1495  if ( ! includes.contains( i ) ) continue;
1496 
1497  s = &data.scanData[ i ];
1498  int start = data.xindex( meniscus_left );
1499  int end = data.xindex( meniscus_right );
1500 
1501  for ( int j = start; j <= end; j++ )
1502  {
1503  if ( maximum < s->rvalues[ j ] )
1504  {
1505  maximum = s->rvalues[ j ];
1506  meniscus = data.radius( j );
1507  }
1508  }
1509  }
1510 
1511  // Remove the left line
1512  if ( v_line != NULL )
1513  {
1514  v_line->detach();
1515  delete v_line;
1516  v_line = NULL;
1517  }
1518  }
1519 
1520  // Display the value
1521  le_meniscus->setText( QString::number( meniscus, 'f', 3 ) );
1522 
1523  // Create a marker
1524  if ( dataType != "IP" )
1525  {
1526  marker = new QwtPlotMarker;
1527  QBrush brush( Qt::white );
1528  QPen pen ( brush, 2.0 );
1529 
1530  marker->setValue( meniscus, maximum );
1531  marker->setSymbol( QwtSymbol(
1532  QwtSymbol::Cross,
1533  brush,
1534  pen,
1535  QSize ( 8, 8 ) ) );
1536 
1537  marker->attach( data_plot );
1538  }
1539 
1540  data_plot->replot();
1541 
1542  pb_meniscus->setIcon( check );
1543 
1544  if ( dataType == "IP" )
1545  pb_airGap->setEnabled( true );
1546  else
1547  pb_dataRange->setEnabled( true );
1548 
1549  next_step();
1550  break;
1551 
1552  case AIRGAP:
1553  if ( airGap_left == 0.0 )
1554  {
1555  airGap_left = p.x();
1557  }
1558  else
1559  {
1560  // Sometime we get two clicks
1561  if ( qAbs( p.x() - airGap_left ) < 0.020 ) return;
1562 
1563  airGap_right = p.x();
1564 
1565  if ( airGap_right < airGap_left )
1567 
1568  US_DataIO::EditValues edits;
1569  edits.airGapLeft = airGap_left;
1570  edits.airGapRight = airGap_right;
1571 
1572  QList< int > excludes;
1573 
1574  for ( int i = 0; i < data.scanData.size(); i++ )
1575  if ( ! includes.contains( i ) ) edits.excludes << i;
1576 
1577 DbgLv(1) << "AGap: L R" << airGap_left << airGap_right << " AdjIntf";
1579 
1580  // Un-zoom
1581  if ( plot->btnZoom->isChecked() )
1582  plot->btnZoom->setChecked( false );
1583 
1584  // Display the data
1585  QString wkstr;
1586  le_airGap->setText( wkstr.sprintf( "%.3f - %.3f",
1587  airGap_left, airGap_right ) );
1588 
1589  step = RANGE;
1590 DbgLv(1) << "AGap: plot_range()";
1591  plot_range();
1592 
1593  qApp->processEvents();
1594 
1595  pb_airGap ->setIcon( check );
1596  pb_dataRange->setEnabled( true );
1597 
1598  next_step();
1599  }
1600 
1601  break;
1602 
1603  case RANGE:
1604  if ( range_left == 0.0 )
1605  {
1606  if ( v_line != NULL )
1607  {
1608  v_line->detach();
1609  delete v_line;
1610  v_line = NULL;
1611  }
1612 
1613  if ( p.x() <= meniscus )
1614  {
1615  le_dataRange->setText( tr( "**overlaps meniscus**" ) );
1616  break;
1617  }
1618 
1619  range_left = radius_indexed( p.x() );
1621  break;
1622  }
1623  else
1624  {
1625  // Sometime we get two clicks
1626  if ( qAbs( p.x() - range_left ) < 0.020 ) return;
1627 
1628  range_right = radius_indexed( p.x() );
1629 
1630  if ( range_right < range_left )
1632 
1633  if ( dataType == "IP" )
1634  {
1635  US_DataIO::EditValues edits;
1636  edits.rangeLeft = range_left;
1637  edits.rangeRight = range_right;
1638  edits.gapTolerance = ct_gaps->value();
1639 
1640  QList< int > excludes;
1641 
1642  for ( int i = 0; i < data.scanData.size(); i++ )
1643  if ( ! includes.contains( i ) ) edits.excludes << i;
1644 
1645  US_DataIO::calc_integral( data, edits );
1646  }
1647 
1648  // Display the data
1649  QString wkstr;
1650  le_dataRange->setText( wkstr.sprintf( "%.3f - %.3f",
1651  range_left, range_right ) );
1652 
1653  step = PLATEAU;
1654  plot_range();
1655 
1656  qApp->processEvents();
1657 
1658  // Skip the gap check for interference data
1659  if ( dataType != "IP" ) gap_check();
1660 
1661  pb_dataRange->setIcon( check );
1662  pb_plateau ->setEnabled( true );
1663  pb_noise ->setEnabled( true );
1664  pb_spikes ->setEnabled( true );
1665 
1666  if ( ! expIsEquil )
1667  { // non-Equilibrium
1668  next_step();
1669  }
1670 
1671  else
1672  { // Equilibrium
1673 
1674  int index = cb_triple->currentIndex();
1675  int row = cb_rpms ->currentIndex();
1676  int jsd = sd_offs[ index ] + row;
1677  QString arpm = cb_rpms->itemText( row );
1678 
1679  if ( sData[ jsd ].meniscus == 0.0 &&
1680  meniscus > 0.0 )
1681  total_edits++;
1682 
1683  sData[ jsd ].meniscus = meniscus;
1684  sData[ jsd ].dataLeft = range_left;
1685  sData[ jsd ].dataRight = range_right;
1686 
1687  if ( ++row >= cb_rpms->count() )
1688  {
1689  if ( ++index < cb_triple->count() )
1690  {
1691  cb_triple->setCurrentIndex( index );
1692  step = MENISCUS;
1693  QString trsp =
1694  cb_triple->currentText() + " : " + trip_rpms[ 0 ];
1695  le_edtrsp->setText( trsp );
1696 
1697  data = *outData[ index ];
1698  cb_rpms->clear();
1699 
1700  for ( int ii = 0; ii < data.scanData.size(); ii++ )
1701  {
1702  QString arpm =
1703  QString::number( data.scanData[ ii ].rpm );
1704 
1705  if ( ! trip_rpms.contains( arpm ) )
1706  trip_rpms << arpm;
1707  }
1708 
1709  cb_rpms->addItems( trip_rpms );
1710  cb_rpms->setCurrentIndex( 0 );
1711 
1712  set_meniscus();
1713  }
1714 
1715  else
1716  {
1717  pb_write ->setEnabled( true );
1718  ck_writemwl->setEnabled( true );
1719  pb_reviewep->setEnabled( true );
1720  pb_nexttrip->setEnabled( true );
1721  step = FINISHED;
1722  next_step();
1723 
1724  if ( total_edits >= total_speeds )
1725  review_edits();
1726  }
1727  }
1728 
1729  else
1730  {
1731  cb_rpms->setCurrentIndex( row );
1732  step = MENISCUS;
1733  QString trsp =
1734  cb_triple->currentText() + " : " + trip_rpms[ row ];
1735  le_edtrsp->setText( trsp );
1736 
1737  set_meniscus();
1738  }
1739  }
1740 
1741  if ( total_edits >= total_speeds )
1742  {
1743  all_edits = true;
1744  pb_write ->setEnabled( true );
1745  ck_writemwl->setEnabled( true );
1747  }
1748  }
1749 
1750  break;
1751 
1752  case PLATEAU:
1753 
1754  if ( p.x() > range_right )
1755  {
1756  le_plateau->setText( tr( "**beyond data end**" ) );
1757  break;
1758  }
1759 
1760  plateau = radius_indexed( p.x() );
1761 
1762  // Display the data (localize str)
1763  {
1764  QString wkstr;
1765  le_plateau->setText( wkstr.sprintf( "%.3f", plateau ) );
1766  }
1767 
1768  plot_range();
1769  pb_plateau ->setIcon( check );
1770  ct_to->setValue( 0.0 ); // Uncolor all scans
1771  pb_write ->setEnabled( true );
1772  ck_writemwl ->setEnabled( isMwl );
1773  changes_made = true;
1774  next_step();
1775  break;
1776 
1777  case BASELINE:
1778  {
1779  // Use the last scan
1780  US_DataIO::Scan* scan = &data.scanData.last();
1781 
1782  int start = data.xindex( range_left );
1783  int end = data.xindex( range_right );
1784  int pt = data.xindex( p.x() );
1785 
1786  if ( pt - start < 5 || end - pt < 5 )
1787  {
1788  QMessageBox::warning( this,
1789  tr( "Position Error" ),
1790  tr( "The selected point is too close to the edge." ) );
1791  return;
1792  }
1793 
1794  double sum = 0.0;
1795 
1796  // Average the value for +/- 5 points
1797  for ( int j = pt - 5; j <= pt + 5; j++ )
1798  sum += scan->rvalues[ j ];
1799 
1800  double bl = sum / 11.0;
1801  baseline = p.x();
1802 
1803  QString wkstr;
1804  le_baseline->setText( wkstr.sprintf( "%.3f (%.3e)", p.x(), bl ) );
1805  plot_range();
1806  }
1807 
1808  pb_write ->setEnabled( true );
1809  ck_writemwl ->setEnabled( isMwl );
1810  changes_made = true;
1811  next_step();
1812  break;
1813 
1814  default:
1815  break;
1816  }
1817 }
1818 
1819 // Draw a vertical pick line
1820 void US_Edit::draw_vline( double radius )
1821 {
1822  double r[ 2 ];
1823 
1824  r[ 0 ] = radius;
1825  r[ 1 ] = radius;
1826 
1827  QwtScaleDiv* y_axis = data_plot->axisScaleDiv( QwtPlot::yLeft );
1828 
1829  double padding = ( y_axis->upperBound() - y_axis->lowerBound() ) / 30.0;
1830 
1831  double v[ 2 ];
1832  v [ 0 ] = y_axis->upperBound() - padding;
1833  v [ 1 ] = y_axis->lowerBound() + padding;
1834 
1835  v_line = us_curve( data_plot, "V-Line" );
1836  v_line->setData( r, v, 2 );
1837 
1838  QPen pen = QPen( QBrush( Qt::white ), 2.0 );
1839  v_line->setPen( pen );
1840 
1841  data_plot->replot();
1842 }
1843 
1844 // Set the step flag for the next step
1846 {
1847  QPushButton* pb;
1848 
1849  if ( meniscus == 0.0 )
1850  {
1851  step = MENISCUS;
1852  pb = pb_meniscus;
1853  }
1854  else if ( airGap_right == 9.0 && dataType == "IP" )
1855  {
1856  step = AIRGAP;
1857  pb = pb_airGap;
1858  }
1859  else if ( range_right == 9.0 )
1860  {
1861  step = RANGE;
1862  pb = pb_dataRange;
1863  }
1864  else if ( plateau == 0.0 )
1865  {
1866  step = PLATEAU;
1867  pb = pb_plateau;
1868  }
1869 
1870  else
1871  { // All values up to Plateau have been entered: Finished
1872  step = FINISHED;
1873  pb = NULL;
1874  double sum = 0.0;
1875  int pt = data.xindex( range_left );
1876  baseline = data.xvalues[ pt + 5 ];
1877 
1878  if ( !isMwl )
1879  {
1880  // Average the value for +/- 5 points
1881  for ( int jj = pt; jj < pt + 11; jj++ )
1882  sum += data.scanData.last().rvalues[ jj ];
1883 
1884  double bl = sum / 11.0;
1885 
1886  QString str;
1887  le_baseline->setText( str.sprintf( "%.3f (%.3e)", baseline, bl ) );
1888  }
1889  }
1890 
1891  set_pbColors( pb );
1892 }
1893 
1894 // Set up for a meniscus pick
1896 {
1897  le_meniscus ->setText( "" );
1898  le_airGap ->setText( "" );
1899  le_dataRange->setText( "" );
1900  le_plateau ->setText( "" );
1901  le_baseline ->setText( "" );
1902 
1903  meniscus = 0.0;
1904  meniscus_left = 0.0;
1905  airGap_left = 0.0;
1906  airGap_right = 9.0;
1907  range_left = 0.0;
1908  range_right = 9.0;
1909  plateau = 0.0;
1910  baseline = 0.0;
1911 
1912  step = MENISCUS;
1913 
1915  pb_meniscus->setIcon( QIcon() );
1916 
1917  pb_airGap ->setEnabled( false );
1918  pb_airGap ->setIcon( QIcon() );
1919  pb_dataRange->setEnabled( false );
1920  pb_dataRange->setIcon( QIcon() );
1921  pb_plateau ->setEnabled( false );
1922  pb_plateau ->setIcon( QIcon() );
1923  pb_write ->setEnabled( all_edits );
1924  ck_writemwl ->setEnabled( all_edits && isMwl );
1925 
1927 DbgLv(1) << "set_meniscus -- changes_made" << changes_made;
1928  spikes = false;
1929  pb_spikes ->setEnabled( false );
1930  pb_spikes ->setIcon( QIcon() );
1931 
1932  // Clear any existing marker
1933  data_plot->detachItems( QwtPlotItem::Rtti_PlotMarker );
1934 
1935  // Reset data and plot
1936  undo();
1937 
1938  if ( ! expIsEquil )
1939  plot_all();
1940 
1941  else
1942  plot_scan();
1943 }
1944 
1945 // Set up for an Air Gap pick
1947 {
1948  le_airGap ->setText( "" );
1949  le_dataRange->setText( "" );
1950  le_plateau ->setText( "" );
1951  le_baseline ->setText( "" );
1952 
1953  airGap_left = 0.0;
1954  airGap_right = 9.0;
1955  range_left = 0.0;
1956  range_right = 9.0;
1957  plateau = 0.0;
1958  baseline = 0.0;
1959 
1960  step = AIRGAP;
1962  pb_airGap ->setIcon( QIcon() );
1963 
1964  pb_dataRange->setIcon( QIcon() );
1965  pb_plateau ->setEnabled( false );
1966  pb_plateau ->setIcon( QIcon() );
1967  pb_write ->setEnabled( all_edits );
1968  ck_writemwl ->setEnabled( all_edits && isMwl );
1970 
1971  spikes = false;
1972  pb_spikes ->setEnabled( false );
1973  pb_spikes ->setIcon( QIcon() );
1974 
1975  undo();
1976  plot_all();
1977 }
1978 
1979 // Set up for a data range pick
1981 {
1982  le_dataRange->setText( "" );
1983  le_plateau ->setText( "" );
1984  le_baseline ->setText( "" );
1985 
1986  range_left = 0.0;
1987  range_right = 9.0;
1988  plateau = 0.0;
1989  baseline = 0.0;
1990 
1991  step = RANGE;
1993 
1994  pb_dataRange->setIcon( QIcon() );
1995  pb_plateau ->setEnabled( false );
1996  pb_plateau ->setIcon( QIcon() );
1997  pb_write ->setEnabled( all_edits );
1998  ck_writemwl ->setEnabled( all_edits && isMwl );
2000 
2001  spikes = false;
2002  pb_spikes ->setEnabled( false );
2003  pb_spikes ->setIcon( QIcon() );
2004 
2005  undo();
2006 
2007  if ( ! expIsEquil )
2008  plot_all();
2009 
2010  else
2011  plot_scan();
2012 }
2013 
2014 // Set up for a Plateau pick
2016 {
2017  le_plateau ->setText( "" );
2018  le_baseline ->setText( "" );
2019 
2020  plateau = 0.0;
2021  baseline = 0.0;
2022 
2023  step = PLATEAU;
2025 
2026  pb_plateau ->setIcon( QIcon() );
2027  pb_write ->setEnabled( all_edits );
2028  ck_writemwl ->setEnabled( all_edits && isMwl );
2030 
2031  plot_range();
2032  undo();
2033 }
2034 
2035 // Set up for a Fringe Tolerance pick
2036 void US_Edit::set_fringe_tolerance( double /* tolerance */)
2037 {
2038  // This is only valid for interference data
2039  if ( dataType != "IP" ) return;
2040 
2041  // If we haven't yet set the range, just ignore the change
2042  if ( step == MENISCUS || step == AIRGAP || step == RANGE ) return;
2043 
2044  // Reset the data
2045  int index = index_data();
2046  data = *outData[ index ];
2047 
2048  US_DataIO::EditValues edits;
2049  edits.airGapLeft = airGap_left;
2050  edits.airGapRight = airGap_right;
2051 
2052  QList< int > excludes;
2053 
2054  for ( int i = 0; i < data.scanData.size(); i++ )
2055  if ( ! includes.contains( i ) ) edits.excludes << i;
2056 
2058 
2059  edits.rangeLeft = range_left;
2060  edits.rangeRight = range_right;
2061  edits.gapTolerance = ct_gaps->value();
2062 
2063  US_DataIO::calc_integral( data, edits );
2064  replot();
2065 }
2066 
2067 // Plot all curves
2068 void US_Edit::plot_all( void )
2069 {
2070  if ( isMwl )
2071  {
2072  plot_mwl();
2073  return;
2074  }
2075 
2076  if ( plot->btnZoom->isChecked() )
2077  plot->btnZoom->setChecked( false );
2078 
2079  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
2080  v_line = NULL;
2081 
2082  int size = data.pointCount();
2083 
2084  QVector< double > rvec( size );
2085  QVector< double > vvec( size );
2086  double* r = rvec.data();
2087  double* v = vvec.data();
2088 
2089  double maxR = -1.0e99;
2090  double minR = 1.0e99;
2091  double maxV = -1.0e99;
2092  double minV = 1.0e99;
2093 
2094  for ( int i = 0; i < data.scanData.size(); i++ )
2095  {
2096  if ( ! includes.contains( i ) ) continue;
2097 
2098  US_DataIO::Scan* s = &data.scanData[ i ];
2099 
2100  for ( int j = 0; j < size; j++ )
2101  {
2102  r[ j ] = data.xvalues[ j ];
2103  v[ j ] = s ->rvalues[ j ] * invert;
2104 
2105  maxR = qMax( maxR, r[ j ] );
2106  minR = qMin( minR, r[ j ] );
2107  maxV = qMax( maxV, v[ j ] );
2108  minV = qMin( minV, v[ j ] );
2109  }
2110 
2111  QString title = tr( "Raw Data at " )
2112  + QString::number( s->seconds ) + tr( " seconds" )
2113  + " #" + QString::number( i );
2114 
2115  QwtPlotCurve* c = us_curve( data_plot, title );
2116  c->setPaintAttribute( QwtPlotCurve::ClipPolygons, true );
2117  c->setData( r, v, size );
2118  }
2119 
2120  // Reset the scan curves within the new limits
2121  double padR = ( maxR - minR ) / 30.0;
2122  double padV = ( maxV - minV ) / 30.0;
2123 
2124  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
2125  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
2126 
2127  // Reset colors
2128  focus( (int)ct_from->value(), (int)ct_to->value() );
2129  data_plot->replot();
2130 }
2131 
2132 // Plot curves within the picked range
2134 {
2135  if ( plot->btnZoom->isChecked() )
2136  plot->btnZoom->setChecked( false );
2137 
2138  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
2139  v_line = NULL;
2140 
2141  int rsize = data.pointCount();
2142  QVector< double > rvec( rsize );
2143  QVector< double > vvec( rsize );
2144  double* r = rvec.data();
2145  double* v = vvec.data();
2146  double maxR = -1.0e99;
2147  double minR = 1.0e99;
2148  double maxV = -1.0e99;
2149  double minV = 1.0e99;
2150  int indext = cb_triple->currentIndex();
2151 
2152  if ( isMwl )
2153  {
2154  int ccx = indext;
2155  int wvx = cb_lplot->currentIndex();
2156  indext = ccx * nwaveln + wvx;
2157 DbgLv(1) << "plot_range(): ccx wvx indext" << ccx << wvx << indext;
2158  }
2159 
2160  // For each scan
2161  for ( int i = 0; i < data.scanData.size(); i++ )
2162  {
2163  if ( ! includes.contains( i ) ) continue;
2164 
2165  US_DataIO::Scan* s = &data.scanData[ i ];
2166 
2167  int indexLeft = data.xindex( range_left );
2168  int indexRight = data.xindex( range_right );
2169  double menp = 0.0;
2170 
2171  if ( expIsEquil )
2172  {
2173  double rngl = range_left;
2174  double rngr = range_right;
2175  int tScan = i + 1;
2176  int jsd = sd_offs[ indext ];
2177  int ksd = jsd + sd_knts[ indext ];
2178 
2179  for ( int jj = jsd; jj < ksd; jj++ )
2180  {
2181  int sScan = sData[ jj ].first_scan;
2182  int eScan = sData[ jj ].scan_count + sScan - 1;
2183 
2184  if ( tScan < sScan || tScan > eScan )
2185  continue;
2186 
2187  rngl = sData[ jj ].dataLeft;
2188  rngr = sData[ jj ].dataRight;
2189  menp = sData[ jj ].meniscus;
2190  break;
2191  }
2192 
2193  indexLeft = data.xindex( rngl );
2194  indexRight = data.xindex( rngr );
2195 
2196  int inxm = data.xindex( menp );
2197 
2198  if ( inxm < 1 )
2199  return;
2200 
2201  r[ 0 ] = data.xvalues[ inxm ];
2202  v[ 0 ] = s ->rvalues[ indexLeft ];
2203  r[ 2 ] = data.xvalues[ inxm + 2 ];
2204  v[ 2 ] = s ->rvalues[ indexLeft + 4 ];
2205  r[ 1 ] = r[ 0 ];
2206  v[ 1 ] = v[ 2 ];
2207  r[ 3 ] = r[ 2 ];
2208  v[ 3 ] = v[ 0 ];
2209  r[ 4 ] = r[ 0 ];
2210  v[ 4 ] = v[ 0 ];
2211 
2212  QwtPlotCurve* c = us_curve( data_plot, tr( "Meniscus at" ) +
2213  QString::number( tScan ) );
2214  c->setBrush( QBrush( Qt::cyan ) );
2215  c->setPen( QPen( Qt::cyan ) );
2216  c->setData( r, v, 5 );
2217  minR = qMin( minR, r[ 0 ] );
2218  minV = qMin( minV, v[ 0 ] );
2219  }
2220 
2221  int count = 0;
2222 
2223  for ( int j = indexLeft; j <= indexRight; j++ )
2224  {
2225  r[ count ] = data.xvalues[ j ];
2226  v[ count ] = s ->rvalues[ j ] * invert;
2227 
2228  maxR = qMax( maxR, r[ count ] );
2229  minR = qMin( minR, r[ count ] );
2230  maxV = qMax( maxV, v[ count ] );
2231  minV = qMin( minV, v[ count ] );
2232 
2233  count++;
2234  }
2235 
2236  QString title = tr( "Raw Data at " )
2237  + QString::number( s->seconds ) + tr( " seconds" )
2238  + " #" + QString::number( i );
2239 
2240  QwtPlotCurve* c = us_curve( data_plot, title );
2241  c->setData( r, v, count );
2242  }
2243 
2244  // Reset the scan curves within the new limits
2245  double padR = ( maxR - minR ) / 30.0;
2246  double padV = ( maxV - minV ) / 30.0;
2247 
2248  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
2249  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
2250 
2251  // Reset colors
2252  focus( (int)ct_from->value(), (int)ct_to->value() );
2253  data_plot->replot();
2254 }
2255 
2256 // Plot the last picked curve
2258 {
2259  if ( plot->btnZoom->isChecked() )
2260  plot->btnZoom->setChecked( false );
2261 
2262  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
2263  v_line = NULL;
2264  //grid = us_grid( data_plot );
2265 
2266  double maxR = -1.0e99;
2267  double minR = 1.0e99;
2268  double maxV = -1.0e99;
2269  double minV = 1.0e99;
2270 
2271  // Plot only the last scan
2272  US_DataIO::Scan* s = &data.scanData[ includes.last() ];;
2273 
2274  int indexLeft = data.xindex( range_left );
2275  int indexRight = data.xindex( range_right );
2276 
2277  int count = 0;
2278  uint size = s->rvalues.size();
2279  QVector< double > rvec( size );
2280  QVector< double > vvec( size );
2281  double* r = rvec.data();
2282  double* v = vvec.data();
2283 
2284  for ( int j = indexLeft; j <= indexRight; j++ )
2285  {
2286  r[ count ] = data.xvalues[ j ];
2287  v[ count ] = s ->rvalues[ j ] * invert;
2288 
2289  maxR = qMax( maxR, r[ count ] );
2290  minR = qMin( minR, r[ count ] );
2291  maxV = qMax( maxV, v[ count ] );
2292  minV = qMin( minV, v[ count ] );
2293 
2294  count++;
2295  }
2296 
2297  QString title = tr( "Raw Data at " )
2298  + QString::number( s->seconds ) + tr( " seconds" )
2299  + " #" + QString::number( includes.last() );
2300 
2301  QwtPlotCurve* c = us_curve( data_plot, title );
2302  c->setData( r, v, count );
2303 
2304  // Reset the scan curves within the new limits
2305  double padR = ( maxR - minR ) / 30.0;
2306  double padV = ( maxV - minV ) / 30.0;
2307 
2308  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
2309  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
2310 
2311  // Reset colors
2312  focus( (int)ct_from->value(), (int)ct_to->value() );
2313  data_plot->replot();
2314 }
2315 
2316 // Plot a single scan curve
2318 {
2319  int rsize = data.pointCount();
2320  int ssize = data.scanCount();
2321  int count = 0;
2322  QVector< double > rvec( rsize );
2323  QVector< double > vvec( rsize );
2324  double* r = rvec.data();
2325  double* v = vvec.data();
2326 
2327  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
2328  v_line = NULL;
2329 
2330  double maxR = -1.0e99;
2331  double minR = 1.0e99;
2332  double maxV = -1.0e99;
2333  double minV = 1.0e99;
2334  QString srpm = cb_rpms->currentText();
2335 
2336  // Plot only the currently selected scan(s)
2337  //
2338  for ( int ii = 0; ii < ssize; ii++ )
2339  {
2340  US_DataIO::Scan* s = &data.scanData[ ii ];
2341 
2342  QString arpm = QString::number( s->rpm );
2343 
2344  if ( arpm != srpm )
2345  continue;
2346 
2347  count = 0;
2348 
2349  for ( int jj = 0; jj < rsize; jj++ )
2350  {
2351  r[ count ] = data.xvalues[ jj ];
2352  v[ count ] = s ->rvalues[ jj ] * invert;
2353 
2354  maxR = qMax( maxR, r[ count ] );
2355  minR = qMin( minR, r[ count ] );
2356  maxV = qMax( maxV, v[ count ] );
2357  minV = qMin( minV, v[ count ] );
2358 
2359  count++;
2360  }
2361 
2362  QString title = tr( "Raw Data at " )
2363  + QString::number( s->seconds ) + tr( " seconds" )
2364  + " #" + QString::number( ii );
2365 
2366  QwtPlotCurve* c = us_curve( data_plot, title );
2367  c->setData( r, v, count );
2368 
2369  // Reset the scan curves within the new limits
2370  double padR = ( maxR - minR ) / 30.0;
2371  double padV = ( maxV - minV ) / 30.0;
2372 
2373  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
2374  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
2375  }
2376 
2377  data_plot->replot();
2378 }
2379 
2380 // Plot MWL curves
2381 void US_Edit::plot_mwl( void )
2382 {
2383  if ( ! isMwl ) return;
2384 
2385  QString rectype = tr( "Wavelength" );
2386  double recvalu = 250;
2387  int index = index_data();
2388  int ccx = triple_index;
2389  int recndx = cb_lplot ->currentIndex();
2390  QString celchn = celchns.at( ccx );
2391  QString scell = celchn.section( "/", 0, 0 ).simplified();
2392  QString schan = celchn.section( "/", 1, 1 ).simplified();
2393  QString svalu;
2394 
2395 DbgLv(1) << "PlMwl: index celchn" << index << celchn;
2396 
2397  if ( xaxis_radius )
2398  {
2399 DbgLv(1) << "PlMwl: x-r index cc nw rx" << index << ccx << nwavelo << recndx;
2400 DbgLv(1) << "PlMwl: outData size" << outData.size();
2401 DbgLv(1) << "PlMwl: expc_wvlns size" << expc_wvlns.size();
2402  data = *outData[ data_index ];
2403  recvalu = expi_wvlns.at( recndx );
2404  svalu = expc_wvlns.at( recndx );
2405 QString dcell=QString::number(data.cell);
2406 QString dchan=QString(QChar(data.channel));
2407 QString dwavl=QString::number(data.scanData[0].wavelength);
2408 DbgLv(1) << "PlMwl: c triple" << scell << schan << svalu
2409  << "d triple" << dcell << dchan << dwavl;
2410  }
2411 
2412  else
2413  {
2414  index = ccx * nrpoint + recndx;
2415 DbgLv(1) << "PlMwl: x-w index cc nr rx" << index << ccx << nrpoint << recndx;
2416  data = *outData[ 0 ];
2417  rectype = tr( "Radius" );
2418  recvalu = expd_radii.at( recndx );
2419  svalu = expc_radii.at( recndx );
2420  }
2421 DbgLv(1) << "PlMwl: ccx index rtype rval" << ccx << index << rectype << recvalu;
2422 
2423  // Read the data description
2424  QString desc = data.description;
2425 
2426  dataType = QString( QChar( data.type[ 0 ] ) )
2427  + QString( QChar( data.type[ 1 ] ) );
2428 
2429  le_info->setText( runID + " (" + desc + ")" );
2430 
2431  // Plot Title
2432  QString title = tr( "Pseudo Absorbance Data\n"
2433  "Run ID: %1\n"
2434  "Cell: %2 Channel: %3 %4: %5" )
2435  .arg( runID ).arg( scell ).arg( schan )
2436  .arg( rectype ).arg( svalu );
2437 DbgLv(1) << "PlMwl: title" << title;
2438 
2439  data_plot->setTitle ( title );
2440  data_plot->setAxisTitle( QwtPlot::yLeft, tr( "Absorbance (OD)" ) );
2441 
2442  data_plot->detachItems ( QwtPlotItem::Rtti_PlotCurve );
2443  v_line = NULL;
2444 
2445  int nscan = data.scanData.size();
2446  int npoint = xaxis_radius ? nrpoint : nwavelo;
2447  int ptxs = 0;
2448 
2449  if ( step != MENISCUS && xaxis_radius )
2450  {
2451  ptxs = data.xindex( range_left );
2452  npoint = data.xindex( range_right ) - ptxs + 1;
2453  }
2454 DbgLv(1) << "PlMwl: xa_rad" << xaxis_radius << "nsc npt" << nscan << npoint;
2455 
2456  QVector< double > rvec( npoint );
2457  QVector< double > vvec( npoint );
2458  double* rr = rvec.data();
2459  double* vv = vvec.data();
2460 
2461  double maxR = -1.0e99;
2462  double minR = 1.0e99;
2463  double maxV = -1.0e99;
2464  double minV = 1.0e99;
2465  double maxOD = odlimit * 2.0;
2466  double valueV;
2467  int kodlim = 0;
2468 
2469  if ( xaxis_radius )
2470  { // Build normal AUC data plot
2471  data_plot->setAxisTitle( QwtPlot::xBottom, tr( "Radius (cm)" ) );
2472 DbgLv(1) << "PlMwl: START xa_RAD";
2473 
2474  for ( int ii = 0; ii < nscan; ii++ )
2475  {
2476  if ( ! includes.contains( ii ) )
2477  {
2478 DbgLv(1) << "PlMwl: ii" << ii << "NOT INCLUDED";
2479  continue;
2480  }
2481 
2482  US_DataIO::Scan* scn = &data.scanData[ ii ];
2483  int kk = ptxs;
2484 
2485  for ( int jj = 0; jj < npoint; jj++ )
2486  {
2487  rr[ jj ] = data.xvalues[ jj ];
2488  valueV = qMin( maxOD, scn->rvalues[ kk++ ] * invert );
2489  vv[ jj ] = valueV;
2490 
2491  maxR = qMax( maxR, rr[ jj ] );
2492  minR = qMin( minR, rr[ jj ] );
2493  maxV = qMax( maxV, valueV );
2494  minV = qMin( minV, valueV );
2495 
2496  if ( valueV > odlimit )
2497  kodlim++;
2498  }
2499 
2500  QString ctitle = tr( "Raw Data at " )
2501  + QString::number( scn->seconds ) + tr( " seconds" )
2502  + " #" + QString::number( ii );
2503 
2504  QwtPlotCurve* cc = us_curve( data_plot, ctitle );
2505  cc->setPaintAttribute( QwtPlotCurve::ClipPolygons, true );
2506  cc->setData( rr, vv, npoint );
2507  }
2508  pick ->disconnect();
2509  connect( pick, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
2510  SLOT ( mouse ( const QwtDoublePoint& ) ) );
2511 DbgLv(1) << "PlMwl: END xa_RAD kodlim odlimit" << kodlim << odlimit;
2512  }
2513 
2514  else
2515  { // Build plot of radius record with wavelength points
2516 DbgLv(1) << "PlMwl: START xa_WAV";
2517  data_plot->setAxisTitle( QwtPlot::xBottom, tr( "Wavelength (nm)" ) );
2518  QVector< double > wrdata = rdata[ index ];
2519  int dpx = 0;
2520 
2521  for ( int ii = 0; ii < nscan; ii++ )
2522  {
2523  if ( ! includes.contains( ii ) ) continue;
2524 
2525  for ( int jj = 0; jj < npoint; jj++ )
2526  {
2527  rr[ jj ] = expi_wvlns[ jj ];
2528  valueV = qMin( maxOD, wrdata[ dpx++ ] );
2529  vv[ jj ] = valueV;
2530 
2531  maxR = qMax( maxR, rr[ jj ] );
2532  minR = qMin( minR, rr[ jj ] );
2533  maxV = qMax( maxV, valueV );
2534  minV = qMin( minV, valueV );
2535 
2536  if ( valueV > odlimit )
2537  kodlim++;
2538  }
2539 
2540  US_DataIO::Scan* scn = &data.scanData[ ii ];
2541  QString ctitle = tr( "Raw Data at " )
2542  + QString::number( scn->seconds ) + tr( " seconds" )
2543  + " #" + QString::number( ii );
2544 
2545  QwtPlotCurve* cc = us_curve( data_plot, ctitle );
2546  cc->setPaintAttribute( QwtPlotCurve::ClipPolygons, true );
2547  cc->setData( rr, vv, npoint );
2548  }
2549 DbgLv(1) << "PlMwl: END xa_WAV kodlim odlimit" << kodlim << odlimit;
2550  }
2551 
2552  // Reset the scan curves within the new limits
2553  double padR = ( maxR - minR ) / 30.0;
2554  double padV = ( maxV - minV ) / 30.0;
2555  padV = qMax( padV, 0.005 );
2556 
2557  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
2558  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
2559 
2560 DbgLv(1) << "PlMwl: call replot()";
2561  data_plot->replot();
2562 DbgLv(1) << "PlMwl: retn fr replot()";
2563 
2564  // Set the Scan spin boxes
2565  ct_from->setMinValue( 0.0 );
2566  ct_from->setMaxValue( data.scanData.size() );
2567 
2568  ct_to ->setMinValue( 0.0 );
2569  ct_to ->setMaxValue( data.scanData.size() );
2570 
2571  pick ->disconnect();
2572  connect( pick, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
2573  SLOT ( mouse ( const QwtDoublePoint& ) ) );
2574 }
2575 
2576 // Set focus FROM scan value
2577 void US_Edit::focus_from( double scan )
2578 {
2579  int from = (int)scan;
2580  int to = (int)ct_to->value();
2581 
2582  if ( from > to )
2583  {
2584  ct_to->disconnect();
2585  ct_to->setValue( scan );
2586  to = from;
2587 
2588  connect( ct_to, SIGNAL( valueChanged ( double ) ),
2589  SLOT ( focus_to ( double ) ) );
2590  }
2591 
2592  focus( from, to );
2593 }
2594 
2595 // Set focus TO scan value
2596 void US_Edit::focus_to( double scan )
2597 {
2598  int to = (int)scan;
2599  int from = (int)ct_from->value();
2600 
2601  if ( from > to )
2602  {
2603  ct_from->disconnect();
2604  ct_from->setValue( scan );
2605  from = to;
2606 
2607  connect( ct_from, SIGNAL( valueChanged ( double ) ),
2608  SLOT ( focus_from ( double ) ) );
2609  }
2610 
2611  focus( from, to );
2612 }
2613 
2614 // Set focus From/To
2615 void US_Edit::focus( int from, int to )
2616 {
2617  if ( from == 0 )
2618  pb_edit1 ->setEnabled( false );
2619  else
2620  pb_edit1 ->setEnabled( true );
2621 
2622  if ( to == 0 )
2623  pb_excludeRange->setEnabled( false );
2624  else
2625  pb_excludeRange->setEnabled( true );
2626 
2627  QList< int > focus;
2628  int ifrom = qMax( from - 1, 0 );
2629  int ito = qMin( to, includes.size() );
2630 
2631  for ( int ii = ifrom; ii < ito; ii++ )
2632  focus << includes.at( ii );
2633 
2634  set_colors( focus );
2635 }
2636 
2637 // Set curve colors
2638 void US_Edit::set_colors( const QList< int >& focus )
2639 {
2640  // Get pointers to curves
2641  QwtPlotItemList list = data_plot->itemList();
2642  QList< QwtPlotCurve* > curves;
2643 
2644  for ( int i = 0; i < list.size(); i++ )
2645  {
2646  if ( list[ i ]->title().text().contains( "Raw" ) )
2647  curves << dynamic_cast< QwtPlotCurve* >( list[ i ] );
2648  }
2649 
2650  QPen p = curves[ 0 ]->pen();
2651  QBrush b = curves[ 0 ]->brush();
2652  QColor std = US_GuiSettings::plotCurve();
2653  QColor foc = Qt::red;
2654 
2655  // Mark these scans in red
2656  for ( int i = 0; i < curves.size(); i++ )
2657  {
2658  int scnnbr = curves[ i ]->title().text().section( "#", 1, 1 ).toInt();
2659 
2660  if ( focus.contains( scnnbr ) )
2661  {
2662  p.setColor( foc );
2663  b.setColor( foc );
2664  }
2665  else
2666  {
2667  p.setColor( std );
2668  b.setColor( std );
2669  }
2670 
2671  curves[ i ]->setPen ( p );
2672  curves[ i ]->setBrush( b );
2673  }
2674 
2675  data_plot->replot();
2676 }
2677 
2678 // Initialize includes
2680 {
2681  includes.clear();
2682  for ( int i = 0; i < data.scanData.size(); i++ ) includes << i;
2683 }
2684 
2685 // Reset excludes
2687 {
2688  ct_from->disconnect();
2689  ct_from->setValue ( 0 );
2690  ct_from->setMaxValue( includes.size() );
2691  connect( ct_from, SIGNAL( valueChanged ( double ) ),
2692  SLOT ( focus_from ( double ) ) );
2693 
2694  ct_to->disconnect();
2695  ct_to->setValue ( 0 );
2696  ct_to->setMaxValue( includes.size() );
2697  connect( ct_to, SIGNAL( valueChanged ( double ) ),
2698  SLOT ( focus_to ( double ) ) );
2699 
2700  pb_excludeRange->setEnabled( false );
2701  pb_edit1 ->setEnabled( false );
2702 
2703  replot();
2704 }
2705 
2706 // Set excludes as indicated in counters
2708 {
2709  int scanStart = (int)ct_from->value();
2710  int scanEnd = (int)ct_to ->value();
2711 
2712  for ( int i = scanEnd; i >= scanStart; i-- )
2713  includes.removeAt( i - 1 );
2714 
2715  replot();
2716  reset_excludes();
2717 }
2718 
2719 // Show exclusion profile
2721 {
2722  reset_excludes();
2723  US_ExcludeProfile* exclude = new US_ExcludeProfile( includes );
2724 
2725  connect( exclude, SIGNAL( update_exclude_profile( QList< int > ) ),
2726  this , SLOT ( update_excludes ( QList< int > ) ) );
2727 
2728  connect( exclude, SIGNAL( cancel_exclude_profile( void ) ),
2729  this , SLOT ( cancel_excludes ( void ) ) );
2730 
2731  connect( exclude, SIGNAL( finish_exclude_profile( QList< int > ) ),
2732  this , SLOT ( finish_excludes ( QList< int > ) ) );
2733 
2734  exclude->exec();
2735  qApp->processEvents();
2736  delete exclude;
2737 }
2738 
2739 // Update based on exclusion profile
2740 void US_Edit::update_excludes( QList< int > scanProfile )
2741 {
2742 DbgLv(1) << "UPD_EXCL: size excl" << scanProfile.size();
2743  set_colors( scanProfile );
2744 }
2745 
2746 // Cancel all excludes
2748 {
2749  QList< int > focus;
2750  set_colors( focus ); // Focus on no curves
2751 }
2752 
2753 // Process excludes to rebuild include list
2754 void US_Edit::finish_excludes( QList< int > excludes )
2755 {
2756  for ( int i = 0; i < excludes.size(); i++ )
2757  includes.removeAll( excludes[ i ] );
2758 
2759 DbgLv(1) << "FIN_EXCL: sizes excl incl" << excludes.size() << includes.size();
2760  replot();
2761  reset_excludes();
2762 }
2763 
2764 // Edit a scan
2766 {
2767  int index1 = (int)ct_from->value();
2768  int scan = includes[ index1 - 1 ];
2769 
2770  US_EditScan* dialog = new US_EditScan( data.scanData[ scan ], data.xvalues,
2772  connect( dialog, SIGNAL( scan_updated( QList< QPointF > ) ),
2773  SLOT ( update_scan ( QList< QPointF > ) ) );
2774  dialog->exec();
2775  qApp->processEvents();
2776  delete dialog;
2777 }
2778 
2779 // Update scan points
2780 void US_Edit::update_scan( QList< QPointF > changes )
2781 {
2782  // Handle excluded scans
2783  int index1 = (int)ct_from->value();
2784  int current_scan = includes[ index1 - 1 ];
2785  US_DataIO::Scan* s = &data.scanData[ current_scan ];
2786 
2787  for ( int i = 0; i < changes.size(); i++ )
2788  {
2789  int point = (int)changes[ i ].x();
2790  double value = changes[ i ].y();
2791 
2792  s->rvalues[ point ] = value;
2793  }
2794 
2795  // Save changes for writing output
2796  Edits e;
2797  e.scan = current_scan;
2798  e.changes = changes;
2799  changed_points << e;
2800 
2801  // Set data for the curve
2802  int points = data.pointCount();
2803  QVector< double > rvec( points );
2804  QVector< double > vvec( points );
2805  double* r = rvec.data();
2806  double* v = vvec.data();
2807 
2808  int left;
2809  int right;
2810  int count = 0;
2811 
2812  if ( range_left > 0 )
2813  {
2814  left = data.xindex( range_left );
2815  right = data.xindex( range_right );
2816  }
2817  else
2818  {
2819  left = 0;
2820  right = points - 1;
2821  }
2822 
2823  for ( int i = left; i <= right; i++ )
2824  {
2825  r[ count ] = data.xvalues[ i ];
2826  v[ count ] = s ->rvalues[ i ];
2827  count++;
2828  }
2829 
2830  // Find the pointer to the current scan
2831  QwtPlotItemList items = data_plot->itemList();
2832  QString seconds = " " + QString::number( s->seconds );
2833  bool found = false;
2834 
2835  QwtPlotCurve* c;
2836  for ( int i = 0; i < items.size(); i++ )
2837  {
2838  if ( items[ i ]->rtti() == QwtPlotItem::Rtti_PlotCurve )
2839  {
2840  c = dynamic_cast< QwtPlotCurve* >( items[ i ] );
2841  if ( c->title().text().contains( seconds ) )
2842  {
2843  found = true;
2844  break;
2845  }
2846  }
2847  }
2848 
2849  if ( found )
2850  {
2851  // Update the curve
2852  c->setData( r, v, count );
2853  data_plot->replot();
2854  }
2855  else
2856  qDebug() << "Can't find curve!";
2857 
2858 }
2859 
2860 // Handle include profile
2861 void US_Edit::include( void )
2862 {
2863  init_includes();
2864  reset_excludes();
2865 }
2866 
2867 // Reset pushbutton and plot with invert flag change
2869 {
2870  if ( invert == 1.0 )
2871  {
2872  invert = -1.0;
2873  pb_invert->setIcon( check );
2874  }
2875  else
2876  {
2877  invert = 1.0;
2878  pb_invert->setIcon( QIcon() );
2879  }
2880 
2881  replot();
2882 }
2883 
2884 // Remove spikes
2886 {
2887  double smoothed_value;
2888 
2889  // For each scan
2890  for ( int i = 0; i < data.scanData.size(); i++ )
2891  {
2892  US_DataIO::Scan* s = &data.scanData [ i ];
2893 
2894  int start = data.xindex( range_left );
2895  int end = data.xindex( range_right );
2896 
2897  for ( int j = start; j < end; j++ )
2898  {
2899  if ( US_DataIO::spike_check( *s, data.xvalues, j, start, end,
2900  &smoothed_value ) )
2901  {
2902  s->rvalues[ j ] = smoothed_value;
2903 
2904  // If previous consecututive points are interpolated, then
2905  // redo them
2906  int index = j - 1;
2907  unsigned char c = s->interpolated[ index / 8 ];
2908 
2909  while ( c & ( 1 << ( 7 - index % 8 ) ) )
2910  {
2912  index, start, end, &smoothed_value ) )
2913  s->rvalues[ index ] = smoothed_value;
2914 
2915  index--;
2916  c = s->interpolated[ index / 8 ];
2917  }
2918  }
2919  }
2920  }
2921 
2922  pb_spikes->setIcon ( check );
2923  pb_spikes->setEnabled( false );
2924  replot();
2925 }
2926 
2927 // Undo changes
2928 void US_Edit::undo( void )
2929 {
2930  // Copy from outData to data
2931  if ( step < PLATEAU )
2932  data = *outData[ index_data() ];
2933 
2934  // Redo some things depending on type
2935  if ( dataType == "IP" )
2936  {
2937  US_DataIO::EditValues edits;
2938  edits.airGapLeft = airGap_left;
2939  edits.airGapRight = airGap_right;
2940 
2941  edits.rangeLeft = range_left;
2942  edits.rangeRight = range_right;
2943  edits.gapTolerance = ct_gaps->value();
2944 
2945  for ( int i = 0; i < data.scanData.size(); i++ )
2946  if ( ! includes.contains( i ) ) edits.excludes << i;
2947 
2948  if ( step > AIRGAP )
2950 
2951  if ( step > RANGE )
2952  US_DataIO::calc_integral( data, edits );
2953  }
2954 
2955  replot();
2956 
2957  // Reset buttons and structures
2958  pb_residuals->setEnabled( false );
2959 
2960  if ( step < PLATEAU )
2961  {
2962  pb_noise ->setEnabled( false );
2963  pb_spikes->setEnabled( false );
2964  }
2965  else
2966  {
2967  pb_noise ->setEnabled( true );
2968  pb_spikes->setEnabled( true );
2969  }
2970 
2971  spikes = false;
2972  noise_order = 0;
2973 
2974  // Remove icons
2975  pb_noise ->setIcon( QIcon() );
2976  pb_residuals ->setIcon( QIcon() );
2977  pb_spikes ->setIcon( QIcon() );
2978 }
2979 
2980 // Calculate and apply noise
2981 void US_Edit::noise( void )
2982 {
2983  residuals.clear();
2984  US_RiNoise* dialog = new US_RiNoise( data, includes,
2986  int code = dialog->exec();
2987  qApp->processEvents();
2988 
2989  if ( code == QDialog::Accepted )
2990  {
2991  pb_noise ->setIcon( check );
2992  pb_residuals->setEnabled( true );
2993  }
2994  else
2995  pb_residuals->setEnabled( false );
2996 
2997  delete dialog;
2998 }
2999 
3000 // Subtract residuals
3002 {
3003  for ( int i = 0; i < data.scanCount(); i++ )
3004  {
3005  for ( int j = 0; j < data.pointCount(); j++ )
3006  data.scanData[ i ].rvalues[ j ] -= residuals[ i ];
3007  }
3008 
3009  pb_residuals->setEnabled( false );
3010  pb_residuals->setIcon ( check );
3011  replot();
3012 }
3013 
3014 // Select a new triple
3015 void US_Edit::new_triple( int index )
3016 {
3017  triple_index = index;
3018 DbgLv(1) << "EDT:NewTr: tripindex" << triple_index << "chgs" << changes_made;
3019 
3020  if ( changes_made )
3021  {
3022  QMessageBox mb;
3023  mb.setIcon( QMessageBox::Question );
3024  mb.setText( tr( "Ignore Edits?" ) );
3025  mb.setInformativeText(
3026  tr( "Edits have been made. If you want to keep them,\n"
3027  "cancel and write the outputs first." ) );
3028  mb.addButton( tr( "Ignore Edits" ), QMessageBox::RejectRole );
3029  mb.addButton( tr( "Return to previous selection" ), QMessageBox::NoRole );
3030  int result = mb.exec();
3031 
3032  if ( result == QMessageBox::RejectRole )
3033  {
3034  cb_triple->disconnect();
3035  cb_triple->setCurrentIndex( triple_index );
3036  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
3037  SLOT ( new_triple ( int ) ) );
3038  return;
3039  }
3040  }
3041 
3042  // Set up data indexes
3043  rb_radius->setChecked( true );
3044  rb_waveln->setChecked( false );
3045 
3046  index_data();
3047 DbgLv(1) << "EDT:NewTr: trip,data index" << triple_index << data_index;
3048 
3049  if ( isMwl )
3050  { // MWL: restore the wavelengths for the newly selected triple
3051  if ( lrng_bycell )
3052  { // Restore raw lambdas for an individual cell
3053  connect_mwl_ctrls( false );
3054  lambdas_by_cell();
3055  cb_lstart->clear();
3056  cb_lend ->clear();
3057  cb_lstart->addItems( rawc_wvlns );
3058  cb_lend ->addItems( rawc_wvlns );
3059  cb_lstart->setCurrentIndex( 0 );
3060  cb_lend ->setCurrentIndex( nwaveln - 1 );
3061  slambda = rawi_wvlns[ 0 ];
3062  elambda = rawi_wvlns[ nwaveln - 1 ];
3063  dlambda = 1;
3064  le_ltrng ->setText( tr( "%1 raw: %2 %3 to %4" )
3065  .arg( nwaveln ).arg( chlamb ).arg( slambda ).arg( elambda ) );
3066  connect_mwl_ctrls( true );
3067  }
3068 
3069  QVector< int > wvs;
3070  mwl_data.lambdas( wvs, triple_index );
3071  lambda_new_list ( wvs );
3072  le_lxrng ->setText( tr( "%1 MWL exports: %2 %3 to %4,"
3073  " raw index increment %5" )
3074  .arg( nwavelo ).arg( chlamb ).arg( slambda ).arg( elambda )
3075  .arg( dlambda ) );
3076 DbgLv(1) << "EDT:NewTr: nwavelo" << nwavelo;
3077  }
3078 
3079  // Reset for new triple
3080  reset_triple();
3081 
3082  // Need to reconnect after reset
3083  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
3084  SLOT ( new_triple ( int ) ) );
3085 
3086  edata = outData[ data_index ];
3087  data = *edata;
3088  QString swavl = cb_lplot ->currentText();
3089  QString triple = cb_triple->currentText() + ( isMwl ? " / " + swavl : "" );
3090  int idax = triples.indexOf( triple );
3091 DbgLv(1) << "EDT:NewTr: sw tri dx" << swavl << triple << idax;
3092 
3093  // Enable pushbuttons
3094  pb_details ->setEnabled( true );
3095  pb_include ->setEnabled( true );
3096  pb_exclusion->setEnabled( true );
3097  pb_meniscus ->setEnabled( true );
3098  pb_airGap ->setEnabled( true );
3099  pb_dataRange->setEnabled( true );
3100  pb_noise ->setEnabled( true );
3101  pb_plateau ->setEnabled( true );
3102  pb_spikes ->setEnabled( true );
3103  pb_invert ->setEnabled( true );
3104  pb_undo ->setEnabled( true );
3105  pb_write ->setEnabled( all_edits );
3106  ck_writemwl ->setEnabled( all_edits && isMwl );
3107  all_edits = false;
3108  changes_made = all_edits;
3109 
3110  init_includes();
3111 
3112  connect( ct_from, SIGNAL( valueChanged ( double ) ),
3113  SLOT ( focus_from ( double ) ) );
3114 
3115  connect( ct_to, SIGNAL( valueChanged ( double ) ),
3116  SLOT ( focus_to ( double ) ) );
3117 
3118  if ( expIsEquil )
3119  { // Equilibrium
3120  cb_rpms->clear();
3121  trip_rpms.clear();
3122 
3123  for ( int ii = 0; ii < data.scanData.size(); ii++ )
3124  { // build unique-rpm list for triple
3125  QString arpm = QString::number( data.scanData[ ii ].rpm );
3126 
3127  if ( ! trip_rpms.contains( arpm ) )
3128  {
3129  trip_rpms << arpm;
3130  }
3131  }
3132  cb_rpms->addItems( trip_rpms );
3133 
3134  le_edtrsp->setText( cb_triple->currentText() + " : " + trip_rpms[ 0 ] );
3135  }
3136 
3137  else
3138  { // non-Equilibrium: possibly re-do/un-do edits
3139  QString trbase = cb_triple->currentText();
3140  triple = trbase;
3141 
3142  if ( isMwl )
3143  {
3144  plotndx = cb_lplot->currentIndex();
3145  swavl = cb_lplot->currentText();
3146  triple += " / " + swavl;
3147  plotrec = swavl.toInt();
3148  }
3149 
3150  QString fname = editFnames[ idax ];
3151  bool app_edit = ( fname != "none" );
3152 DbgLv(1) << "EDT:NewTr: app_edit" << app_edit << "fname" << fname;
3153 
3154  if ( app_edit )
3155  { // This data has editing, ask if it should be applied
3156  QStringList editfiles;
3157 
3158  if ( fname == "same" )
3159  { // Need to find an edit file for this channel
3160  QString celchn = trbase + " / ";
3161  int wvxe = nwavelo - 1;
3162 DbgLv(1) << "EDT:NewTr: wvxe ewvsiz" << wvxe << expc_wvlns.count();
3163  int jdax = triples.indexOf( celchn + expc_wvlns[ 0 ] );
3164  int ldax = triples.indexOf( celchn + expc_wvlns[ wvxe ] );
3165 DbgLv(1) << "EDT:NewTr: jdax ldax" << jdax << ldax;
3166 
3167  while ( jdax <= ldax )
3168  {
3169  if ( editFnames[ jdax ].length() > 4 )
3170  {
3171  fname = editFnames[ jdax ];
3172  idax = jdax;
3173  break;
3174  }
3175 
3176  jdax++;
3177  }
3178  }
3179 
3180  QString trtype = isMwl ? "cell/channel" : "triple";
3181  QString trvalu = isMwl ? trbase : triple;
3182 DbgLv(1) << "EDT:NewTr: tr type,valu" << trtype << trvalu;
3183 
3184  QMessageBox mbox;
3185  QPushButton* pb_appl;
3186  QString msg = tr( "Edits have been loaded or saved<br/>"
3187  "for the current %1 (%2).<br/></br/>"
3188  "Do you wish to<br/>"
3189  "&nbsp;&nbsp;"
3190  "apply them (<b>Apply Edits</b>) or<br/>"
3191  "&nbsp;&nbsp;"
3192  "ignore them (<b>Ignore Edits</b>)<br/>"
3193  "in data displays?" )
3194  .arg( trtype ).arg( trvalu );
3195  mbox.setIcon ( QMessageBox::Question );
3196  mbox.setIcon ( QMessageBox::Question );
3197  mbox.setTextFormat( Qt::RichText );
3198  mbox.setText ( msg );
3199  mbox.addButton( tr( "Ignore Edits" ),
3200  QMessageBox::RejectRole );
3201  pb_appl = mbox.addButton( tr( "Apply Edits" ),
3202  QMessageBox::AcceptRole );
3203  mbox.setDefaultButton( pb_appl );
3204  mbox.exec();
3205  app_edit = ( mbox.clickedButton() == pb_appl );
3206  }
3207 
3208  if ( app_edit )
3209  { // If editing chosen, apply it
3210  US_DataIO::EditValues parameters;
3211 
3212  US_DataIO::readEdits( workingDir + fname, parameters );
3213 
3214  apply_edits( parameters );
3215  }
3216 
3217  else
3218  { // If no editing, be sure to turn off edits
3219  set_meniscus();
3220  }
3221 
3222 DbgLv(1) << "EDT:NewTr: men" << meniscus << "dx" << idax;
3223  plot_current( idax );
3224  }
3225 
3226  replot();
3227 DbgLv(1) << "EDT:NewTr: DONE";
3228 }
3229 
3230 // Select a new speed within a triple
3231 void US_Edit::new_rpmval( int index )
3232 {
3233  QString srpm = cb_rpms->itemText( index );
3234 
3235  set_meniscus();
3236 
3237  le_edtrsp->setText( cb_triple->currentText() + " : " + srpm );
3238 
3239  plot_scan();
3240 }
3241 
3242 // Mark data as floating
3243 void US_Edit::floating( void )
3244 {
3246  if ( floatingData )
3247  pb_float->setIcon( check );
3248  else
3249  pb_float->setIcon( QIcon() );
3250 
3251 }
3252 
3253 // Save edit profile(s)
3254 void US_Edit::write( void )
3255 {
3256  if ( !expIsEquil )
3257  { // non-Equilibrium: write single current edit (if "all" unchecked)
3258  if ( isMwl && ck_writemwl->isChecked() )
3259  { // Write edits for all triples in the current cell/channel
3260  write_mwl();
3261  }
3262 
3263  else
3264  { // Write single triple's edit
3265  triple_index = cb_triple->currentIndex();
3266 
3267  write_triple();
3268  }
3269  }
3270 
3271  else
3272  { // Equilibrium: loop to write all edits
3273  for ( int jr = 0; jr < triples.size(); jr++ )
3274  {
3275  triple_index = jr;
3276  data = *outData[ jr ];
3277 
3278  write_triple();
3279  }
3280  }
3281 
3282  changes_made = false;
3283  pb_write ->setEnabled( false );
3284  ck_writemwl ->setEnabled( false );
3285 }
3286 
3287 // Save edits for a triple
3289 {
3290  QString s;
3291 
3292  meniscus = le_meniscus->text().toDouble();
3293  baseline = data.xvalues[ data.xindex( range_left ) + 5 ];
3294  int odax = cb_triple->currentIndex();
3295  int idax = odax;
3296 
3297  if ( isMwl )
3298  { // For MultiWavelength, data index needs to be recomputed
3299  int wvx = cb_lplot ->currentIndex();
3300  QString swavl = expc_wvlns[ wvx ];
3301  QString triple = cb_triple->currentText() + " / " + swavl;
3302  idax = triples.indexOf( triple );
3303  odax = index_data( wvx );
3304  }
3305 
3306  if ( expIsEquil )
3307  { // Equilibrium: set baseline,plateau as flag that those are "done"
3308  int jsd = sd_offs[ triple_index ];
3309  meniscus = sData[ jsd ].meniscus;
3310  range_left = sData[ jsd ].dataLeft;
3311  range_right = sData[ jsd ].dataRight;
3312  baseline = range_left;
3313  plateau = range_right;
3314  }
3315 
3316  // Check if complete
3317  if ( meniscus == 0.0 )
3318  s = tr( "meniscus" );
3319  else if ( dataType == "IP" && ( airGap_left == 0.0 || airGap_right == 9.0 ) )
3320  s = tr( "air gap" );
3321  else if ( range_left == 0.0 || range_right == 9.0 )
3322  s = tr( "data range" );
3323  else if ( plateau == 0.0 )
3324  s = tr( "plateau" );
3325  else if ( baseline == 0.0 )
3326  s = tr( "baseline" );
3327 
3328  if ( ! s.isEmpty() )
3329  {
3330  QMessageBox::information( this,
3331  tr( "Data missing" ),
3332  tr( "You must define the " ) + s
3333  + tr( " before writing the edit profile." ) );
3334  return;
3335  }
3336 
3337  // Check if meniscus and plateau are consistent with the data range
3338  if ( meniscus >= range_left )
3339  {
3340  QMessageBox::critical( this,
3341  tr( "Meniscus/Data_Left Inconsistent" ),
3342  tr( "The specified Meniscus (%1) extends into the "
3343  "Data Range (%2 to %3). Correct the Meniscus/Data_Left" )
3344  .arg( meniscus ).arg( range_left ).arg( range_right ) );
3345  return;
3346  }
3347 
3348  if ( plateau >= range_right )
3349  {
3350  QMessageBox::critical( this,
3351  tr( "Plateau/Data_Right Inconsistent" ),
3352  tr( "The specified Plateau (%1) is outside of the "
3353  "Data Range (%2 to %3). Correct the Meniscus/Data_Right" )
3354  .arg( plateau ).arg( range_left ).arg( range_right ) );
3355  return;
3356  }
3357 
3358  QString sufx = "";
3359 
3360  // Ask for editLabel if not yet defined
3361  while ( editLabel.isEmpty() )
3362  {
3363  QString now = QDateTime::currentDateTime()
3364  .toUTC().toString( "yyMMddhhmm" );
3365 
3366  bool ok;
3367  QString msg = tr( "The base Edit Label for this edit session is <b>" )
3368  + now + "</b> .<br/>"
3369  + tr( "You may add an optional suffix to further distinquish<br/>"
3370  "the Edit Label. Use alphanumeric characters, underscores,<br/>"
3371  "or hyphens (no spaces). Enter 0 to 10 suffix characters." );
3372  sufx = QInputDialog::getText( this,
3373  tr( "Create a unique session Edit Label" ),
3374  msg,
3375  QLineEdit::Normal,
3376  sufx,
3377  &ok );
3378 
3379  if ( ! ok ) return;
3380 
3381  sufx.remove( QRegExp( "[^\\w\\d_-]" ) );
3382  editLabel = now + sufx;
3383 
3384  if ( editLabel.length() > 20 )
3385  {
3386  QMessageBox::critical( this,
3387  tr( "Text length error" ),
3388  tr( "You entered %1 characters for the Edit Label suffix.\n"
3389  "Re-enter, limiting length to 10 characters." )
3390  .arg( sufx.length() ) );
3391  editLabel.clear();
3392  sufx = sufx.left( 10 );
3393  }
3394  }
3395 
3396  // Determine file name
3397  // workingDir + runID + editLabel + data type + cell + channel + wavelength
3398  // + ".xml"
3399 
3400  QString filename = files[ idax ];
3401 DbgLv(1) << "EDT:WrTripl: tripindex" << triple_index << "idax" << idax
3402  << "filename" << filename;
3403  QString rpart = filename.section( ".", 0, -6 );
3404  QString tpart = filename.section( ".", -5, -2 );
3405  filename = rpart + "." + editLabel + "." + tpart + ".xml";
3406  QString wvpart = "";
3407 DbgLv(1) << "EDT:WrTripl: filename" << filename;
3408 
3409  if ( expType.isEmpty() ||
3410  expType.compare( "other", Qt::CaseInsensitive ) == 0 )
3411  expType = "Velocity";
3412 
3413  QString editGUID = editGUIDs[ idax ];
3414 
3415  if ( editGUID.isEmpty() )
3416  {
3417  editGUID = US_Util::new_guid();
3418  editGUIDs.replace( idax, editGUID );
3419  }
3420 
3421  QString rawGUID = US_Util::uuid_unparse( (unsigned char*)data.rawGUID );
3422  QString triple = triples.at( idax );
3423 DbgLv(1) << "EDT:WrTripl: triple" << triple;
3424 
3425  // Output the edit XML file
3426  int wrstat = write_xml_file( filename, triple, editGUID, rawGUID );
3427 
3428  if ( wrstat != 0 )
3429  return;
3430  else
3431  editFnames[ idax ] = filename;
3432 
3433  if ( disk_controls->db() )
3434  {
3435  if ( dbP == NULL )
3436  {
3437  US_Passwd pw;
3438  dbP = new US_DB2( pw.getPasswd() );
3439  if ( dbP == NULL || dbP->lastErrno() != US_DB2::OK )
3440  {
3441  QMessageBox::warning( this, tr( "Connection Problem" ),
3442  tr( "Could not connect to database \n" ) + dbP->lastError() );
3443  return;
3444  }
3445  }
3446 
3447  QString editID = editIDs[ idax ];
3448 
3449  // Output the edit database record
3450  wrstat = write_edit_db( dbP, filename, editGUID, editID, rawGUID );
3451 
3452  if ( wrstat != 0 )
3453  return;
3454  }
3455 }
3456 
3457 // Apply a prior edit profile for Velocity and like data
3459 {
3460  QString filename;
3461  QString filepath;
3462  int index1;
3463  US_DB2* dbP = NULL;
3464 DbgLv(1) << "AppPri: IN dkdb" << disk_controls->db();
3465 
3466  if ( disk_controls->db() )
3467  {
3468  US_Passwd pw;
3469  dbP = new US_DB2( pw.getPasswd() );
3470 
3471  if ( dbP->lastErrno() != US_DB2::OK )
3472  {
3473  QMessageBox::warning( this, tr( "Connection Problem" ),
3474  tr( "Could not connect to database: \n" ) + dbP->lastError() );
3475  return;
3476  }
3477 
3478  QStringList q( "get_rawDataID_from_GUID" );
3479 
3480  q << US_Util::uuid_unparse( (uchar*)data.rawGUID );
3481  dbP->query( q );
3482 
3483  // Error check
3484  if ( dbP->lastErrno() != US_DB2::OK )
3485  {
3486  QMessageBox::warning( this,
3487  tr( "AUC Data is not in DB" ),
3488  tr( "Cannot find the raw data in the database.\n" ) );
3489 
3490  return;
3491  }
3492 
3493  dbP->next();
3494  QString rawDataID = dbP->value( 0 ).toString();
3495 
3496  q.clear();
3497  q << "get_editedDataIDs" << rawDataID;
3498 
3499  dbP->query( q );
3500 
3501 
3502  QStringList editDataIDs;
3503  QStringList filenames;
3504 
3505  while ( dbP->next() )
3506  {
3507  editDataIDs << dbP->value( 0 ).toString();
3508  filenames << dbP->value( 2 ).toString();
3509  }
3510 
3511  if ( editDataIDs.size() == 0 )
3512  {
3513  QMessageBox::warning( this,
3514  tr( "Edit data is not in DB" ),
3515  tr( "Cannot find any edit records in the database.\n" ) );
3516 
3517  return;
3518  }
3519 
3520  int index;
3521  US_GetEdit dialog( index, filenames );
3522  if ( dialog.exec() == QDialog::Rejected ) return;
3523 
3524  if ( index >= 0 )
3525  {
3526  filepath = workingDir + filenames[ index ];
3527  int dataID = editDataIDs[ index ].toInt();
3528  dbP->readBlobFromDB( filepath, "download_editData", dataID );
3529  }
3530  }
3531  else
3532  {
3533  QString filter = files[ cb_triple->currentIndex() ];
3534  index1 = filter.indexOf( '.' ) + 1;
3535 
3536  filter = "*" + filter.mid( index1 );
3537  filter.replace( QRegExp( "auc$" ), "xml" );
3538  filter = tr( "Edits(" ) + filter + tr( ");;All XML (*.xml)" );
3539 
3540  // Ask for edit file
3541  filepath = QFileDialog::getOpenFileName( this,
3542  tr( "Select a saved edit file" ),
3543  workingDir, filter );
3544  }
3545 DbgLv(1) << "AppPri: fpath" << filepath;
3546 
3547  if ( filepath.isEmpty() ) return;
3548 
3549  // Get multiple edits if they exist and user so chooses
3550  QStringList editfiles;
3551  filepath = filepath.replace( "\\", "/" );
3552  filename = filepath.section( "/", -1, -1 );
3553  QString triple = filename.section( ".", -4, -2 )
3554  .replace( ".", " / " );
3555  int idax = triples.indexOf( triple );
3556 
3557  int nledits = like_edit_files( filename, editfiles, dbP );
3558 DbgLv(1) << "AppPri: nledits" << nledits << editfiles.count();
3559 
3560  if ( nledits > 1 )
3561  {
3562  QPushButton* pb_defb;
3563  QPushButton* pb_selo;
3564  QPushButton* pb_allw;
3565  QString edtLbl = editfiles[ 0 ].section( ".", -6, -6 );
3566  int swavl = editfiles[ 0 ].section( ".", -2, -2 ).toInt();
3567  int ewavl = editfiles[ nledits - 1 ].section( ".", -2, -2 ).toInt();
3568 
3569  QMessageBox mbox;
3570  QString msg = tr( "%1 wavelengths (%2 to %3) have the same<br/>"
3571  "Edit Label of \"%4\" as the selected file.<br/>"
3572  "<br/>"
3573  "Specify whether you wish to apply edits only<br/>"
3574  "to the selected file (<b>Selected Only</b>)<br/>"
3575  "or to apply them to all wavelengths of the<br/>"
3576  "current cell/channel (<b>All Wavelengths</b>)." )
3577  .arg( nledits ).arg( swavl ).arg( ewavl ).arg( edtLbl );
3578  mbox.setIcon ( QMessageBox::Question );
3579  mbox.setTextFormat( Qt::RichText );
3580  mbox.setText ( msg );
3581  pb_selo = mbox.addButton( tr( "Selected Only" ),
3582  QMessageBox::RejectRole );
3583  pb_allw = mbox.addButton( tr( "All Wavelengths" ),
3584  QMessageBox::AcceptRole );
3585  pb_defb = nledits > 2 ? pb_allw : pb_selo;
3586  mbox.setDefaultButton( pb_defb );
3587  mbox.exec();
3588 
3589  if ( mbox.clickedButton() == pb_selo )
3590  { // Only apply for the selected file
3591 DbgLv(1) << "AppPri: SelOnly button clicked";
3592  nledits = 1;
3593  editfiles.clear();
3594  editfiles << filename;
3595 
3596  editFnames[ idax ] = filename;
3597  }
3598 
3599  else
3600  { // Apply to all like-labeled wavelengths in the channel
3601 DbgLv(1) << "AppPri: AllWavl button clicked";
3602  for ( int ii = 0; ii < nledits; ii++ )
3603  { // Save selected edit file name; use "same" for others in channel
3604  QString edfile = editfiles[ ii ];
3605  QString triple = edfile.section( ".", -4, -2 )
3606  .replace( ".", " / " );
3607  int jdax = triples.indexOf( triple );
3608 
3609  if ( edfile != filename )
3610  { // The selected file
3611  editFnames[ jdax ] = filename;
3612  }
3613 
3614  else
3615  { // Non-selected file
3616  editFnames[ jdax ] = QString( "same" );
3617  }
3618  }
3619  }
3620  }
3621 
3622  else
3623  { // Save edit file name for the single triple
3624  editFnames[ idax ] = filename;
3625  }
3626 
3627  // Reset data from input data
3628  data = allData[ idax ];
3629 
3630  // Read the edits
3631  US_DataIO::EditValues parameters;
3632 
3633  int result = US_DataIO::readEdits( filepath, parameters );
3634 
3635  if ( result != US_DataIO::OK )
3636  {
3637  QMessageBox::warning( this,
3638  tr( "XML Error" ),
3639  tr( "An error occurred when reading edit file\n\n" )
3640  + US_DataIO::errorString( result ) );
3641  return;
3642  }
3643 
3644  QString uuid = US_Util::uuid_unparse( (unsigned char*)data.rawGUID );
3645 
3646  if ( parameters.dataGUID != uuid )
3647  {
3648  QMessageBox::warning( this,
3649  tr( "Data Error" ),
3650  tr( "The edit file was not created using the current data" ) );
3651 DbgLv(1) << "parsGUID rawGUID" << parameters.dataGUID << uuid;
3652  return;
3653  }
3654 
3655  // Apply the edits with specified parameters
3656  apply_edits( parameters );
3657 
3658  pb_undo ->setEnabled( true );
3659  pb_write ->setEnabled( true );
3660  ck_writemwl->setEnabled( isMwl );
3661 
3662  changes_made= false;
3663  plot_range();
3664 }
3665 
3666 // Apply prior edits to an Equilibrium set
3668 {
3669  int cndxt = cb_triple->currentIndex();
3670  int cndxs = cb_rpms ->currentIndex();
3671  int index1;
3672  QString filename;
3673  QStringList cefnames;
3674  data = *outData[ 0 ];
3675 
3676  if ( disk_controls->db() )
3677  { // Get prior equilibrium edits from DB
3678  US_Passwd pw;
3679  US_DB2 db( pw.getPasswd() );
3680 
3681  if ( db.lastErrno() != US_DB2::OK )
3682  {
3683  QMessageBox::warning( this, tr( "Connection Problem" ),
3684  tr( "Could not connect to database \n" ) + db.lastError() );
3685  return;
3686  }
3687 
3688  QStringList q( "get_rawDataID_from_GUID" );
3689 
3690  q << US_Util::uuid_unparse( (uchar*)data.rawGUID );
3691 
3692  db.query( q );
3693 
3694  // Error check
3695  if ( db.lastErrno() != US_DB2::OK )
3696  {
3697  QMessageBox::warning( this,
3698  tr( "AUC Data is not in DB" ),
3699  tr( "Cannot find the raw data in the database.\n" ) );
3700 
3701  return;
3702  }
3703 
3704  db.next();
3705  QString rawDataID = db.value( 0 ).toString();
3706 
3707  q.clear();
3708  q << "get_editedDataIDs" << rawDataID;
3709 
3710  db.query( q );
3711 
3712 
3713  QStringList editDataIDs;
3714  QStringList filenames;
3715 
3716  while ( db.next() )
3717  {
3718  editDataIDs << db.value( 0 ).toString();
3719  filenames << db.value( 2 ).toString();
3720  }
3721 
3722  if ( editDataIDs.size() == 0 )
3723  {
3724  QMessageBox::warning( this,
3725  tr( "Edit data is not in DB" ),
3726  tr( "Cannot find any edit records in the database.\n" ) );
3727 
3728  return;
3729  }
3730 
3731  int index;
3732  US_GetEdit dialog( index, filenames );
3733  if ( dialog.exec() == QDialog::Rejected ) return;
3734 
3735  if ( index < 0 )
3736  return;
3737 
3738  filename = filenames[ index ];
3739  int dataID = editDataIDs[ index ].toInt();
3740 
3741  QString editLabel = filename.section( ".", -6, -6 );
3742  filename = workingDir + filename;
3743  db.readBlobFromDB( filename, "download_editData", dataID );
3744 
3745  cefnames << filename; // save the first file name
3746 
3747  // Loop to get files with same Edit Label from other triples
3748  for ( int ii = 1; ii < outData.size(); ii++ )
3749  {
3750  data = *outData[ ii ];
3751  q.clear();
3752  q << "get_rawDataID_from_GUID"
3753  << US_Util::uuid_unparse( (uchar*)data.rawGUID );
3754  db.query( q );
3755  db.next();
3756  rawDataID = db.value( 0 ).toString();
3757 
3758  q.clear();
3759  q << "get_editedDataIDs" << rawDataID;
3760  db.query( q );
3761  filename.clear();
3762  bool found = false;
3763 
3764  while ( db.next() )
3765  {
3766  dataID = db.value( 0 ).toString().toInt();
3767  filename = db.value( 2 ).toString();
3768  QString elb = filename.section( ".", -6, -6 );
3769 
3770  if ( elb == editLabel )
3771  {
3772  found = true;
3773  filename = workingDir + filename;
3774  db.readBlobFromDB( filename, "download_editData", dataID );
3775  cefnames << filename;
3776  break;
3777  }
3778  }
3779 
3780  if ( ! found )
3781  cefnames << "";
3782  }
3783  }
3784 
3785  else
3786  { // Get prior equilibrium edits from Local Disk
3787  QString filter = files[ cb_triple->currentIndex() ];
3788  index1 = filter.indexOf( '.' ) + 1;
3789 
3790  filter.insert( index1, "*." );
3791  filter.replace( QRegExp( "auc$" ), "xml" );
3792 
3793  // Ask for edit file
3794  filename = QFileDialog::getOpenFileName( this,
3795  tr( "Select a saved edit file" ),
3796  workingDir, filter );
3797 
3798  if ( filename.isEmpty() ) return;
3799 
3800  filename = filename.replace( "\\", "/" );
3801  QString editLabel = filename.section( "/", -1, -1 ).section( ".", -6, -6 );
3802  QString runID = filename.section( "/", -1, -1 ).section( ".", 0, -7 );
3803 
3804  for ( int ii = 0; ii < files.size(); ii++ )
3805  {
3806  filename = files[ ii ];
3807  filename = runID + "." + editLabel + "."
3808  + filename.section( ".", -5, -2 ) + ".xml";
3809  filename = workingDir + filename;
3810 
3811  if ( QFile( filename ).exists() )
3812  cefnames << filename;
3813 
3814  else
3815  cefnames << "";
3816  }
3817  }
3818 
3819  for ( int ii = 0; ii < cefnames.size(); ii++ )
3820  { // Read and apply edits from edit files
3821  data = *outData[ ii ];
3822  filename = cefnames[ ii ];
3823 
3824  // Read the edits
3825  US_DataIO::EditValues parameters;
3826 
3827  int result = US_DataIO::readEdits( filename, parameters );
3828 
3829  if ( result != US_DataIO::OK )
3830  {
3831  QMessageBox::warning( this,
3832  tr( "XML Error" ),
3833  tr( "An error occurred when reading edit file\n\n" )
3834  + US_DataIO::errorString( result ) );
3835  continue;
3836  }
3837 
3838  QString uuid = US_Util::uuid_unparse( (unsigned char*)data.rawGUID );
3839 
3840  if ( parameters.dataGUID != uuid )
3841  {
3842  QMessageBox::warning( this,
3843  tr( "Data Error" ),
3844  tr( "The edit file was not created using the current data" ) );
3845  continue;
3846  }
3847 
3848  // Apply the edits
3849  QString wkstr;
3850 
3851  meniscus = parameters.meniscus;
3852  range_left = parameters.rangeLeft;
3853  range_right = parameters.rangeRight;
3854  plateau = parameters.plateau;
3855  baseline = parameters.baseline;
3856 
3857  if ( parameters.speedData.size() > 0 )
3858  {
3859  meniscus = parameters.speedData[ 0 ].meniscus;
3860  range_left = parameters.speedData[ 0 ].dataLeft;
3861  range_right = parameters.speedData[ 0 ].dataRight;
3862  baseline = range_left;
3863  plateau = range_right;
3864 
3865  int jsd = sd_offs[ ii ];
3866 
3867  for ( int jj = 0; jj < sd_knts[ ii ]; jj++ )
3868  sData[ jsd++ ] = parameters.speedData[ jj ];
3869  }
3870 
3871  le_meniscus->setText( wkstr.sprintf( "%.3f", meniscus ) );
3872  pb_meniscus->setIcon( check );
3873  pb_meniscus->setEnabled( true );
3874 
3875  airGap_left = parameters.airGapLeft;
3876  airGap_right = parameters.airGapRight;
3877 
3878  if ( dataType == "IP" )
3879  {
3880  US_DataIO::adjust_interference( data, parameters );
3881  US_DataIO::calc_integral ( data, parameters );
3882  le_airGap->setText( wkstr.sprintf( "%.3f - %.3f",
3883  airGap_left, airGap_right ) );
3884  pb_airGap->setIcon( check );
3885  pb_airGap->setEnabled( true );
3886  }
3887 
3888  le_dataRange->setText( wkstr.sprintf( "%.3f - %.3f",
3889  range_left, range_right ) );
3890  pb_dataRange->setIcon( check );
3891  pb_dataRange->setEnabled( true );
3892 
3893  // Invert
3894  invert = parameters.invert;
3895 
3896  if ( invert == -1.0 ) pb_invert->setIcon( check );
3897  else pb_invert->setIcon( QIcon() );
3898 
3899  // Excluded scans
3900  init_includes();
3901  reset_excludes(); // Zero exclude combo boxes
3902  qSort( parameters.excludes );
3903 
3904  for ( int i = parameters.excludes.size(); i > 0; i-- )
3905  includes.removeAt( parameters.excludes[ i - 1 ] );
3906 
3907  // Edited points
3908  changed_points.clear();
3909 
3910  for ( int i = 0; i < parameters.editedPoints.size(); i++ )
3911  {
3912  int scan = parameters.editedPoints[ i ].scan;
3913  int index1 = (int)parameters.editedPoints[ i ].radius;
3914  double value = parameters.editedPoints[ i ].value;
3915 
3916  Edits e;
3917  e.scan = scan;
3918  e.changes << QPointF( index1, value );
3919 
3920  changed_points << e;
3921 
3922  data.scanData[ scan ].rvalues[ index1 ] = value;
3923  }
3924 
3925  // Spikes
3926  spikes = parameters.removeSpikes;
3927 
3928  pb_spikes->setIcon( QIcon() );
3929  pb_spikes->setEnabled( true );
3930  if ( spikes ) remove_spikes();
3931 
3932  // Noise
3933  noise_order = parameters.noiseOrder;
3934  if ( noise_order > 0 )
3935  {
3938 
3940  }
3941  else
3942  {
3943  pb_noise ->setIcon( QIcon() );
3944  pb_residuals->setIcon( QIcon() );
3945  pb_residuals->setEnabled( false );
3946  }
3947 
3948  // Floating data
3949  floatingData = parameters.floatingData;
3950 
3951  if ( floatingData )
3952  pb_float->setIcon( check );
3953 
3954  else
3955  pb_float->setIcon( QIcon() );
3956  }
3957 
3958  step = FINISHED;
3959  set_pbColors( NULL );
3960 
3961  pb_undo ->setEnabled( true );
3962  pb_write ->setEnabled( true );
3963  ck_writemwl->setEnabled( isMwl );
3964 
3965  cndxt = ( cndxt < 0 ) ? 0 : cndxt;
3966  cndxs = ( cndxs < 0 ) ? 0 : cndxs;
3967  cb_triple->setCurrentIndex( cndxt );
3968  cb_rpms ->setCurrentIndex( cndxs );
3969 
3970  //changes_made= false;
3971  //plot_range();
3972 
3973  pb_reviewep->setEnabled( true );
3974  pb_nexttrip->setEnabled( true );
3975 
3977  pb_write ->setEnabled( all_edits );
3978  ck_writemwl->setEnabled( all_edits && isMwl );
3980 
3981  review_edits();
3982 }
3983 
3984 // Initialize edit review for first triple
3986 {
3987  cb_triple->disconnect();
3988  cb_triple->setCurrentIndex( cb_triple->count() - 1 );
3989 
3990  le_meniscus ->setText( "" );
3991  le_dataRange->setText( "" );
3992  pb_plateau ->setIcon( QIcon() );
3993  pb_dataRange->setIcon( QIcon() );
3994  pb_meniscus ->setIcon( QIcon() );
3995 
3996  step = FINISHED;
3997  next_triple();
3998 }
3999 
4000 // Advance to next triple and plot edited curves
4002 {
4003  int row = cb_triple->currentIndex() + 1;
4004  row = ( row < cb_triple->count() ) ? row : 0;
4005 
4006  cb_triple->disconnect();
4007  cb_triple->setCurrentIndex( row );
4008  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
4009  SLOT ( new_triple ( int ) ) );
4010 
4011  if ( le_edtrsp->isVisible() )
4012  {
4013  QString trsp = cb_triple->currentText() + " : " + trip_rpms[ 0 ];
4014  le_edtrsp->setText( trsp );
4015  cb_rpms ->setCurrentIndex( 0 );
4016  }
4017 
4018  data = *outData[ index_data() ];
4019  plot_range();
4020 }
4021 
4022 // Evaluate whether all edits are complete
4024 {
4025  bool all_ed_done = false;
4026 
4027  if ( expIsEquil )
4028  {
4029  total_edits = 0;
4030  total_speeds = 0;
4031 
4032  for ( int jd = 0; jd < outData.size(); jd++ )
4033  { // Examine each data set to evaluate whether edits complete
4034  int jsd = sd_offs[ jd ];
4035  int ksd = jsd + sd_knts[ jd ];
4036  QList< double > drpms;
4037  US_DataIO::RawData* rawdat = outData[ jd ];
4038 
4039  // Count edits done on this data set
4040  for ( int js = jsd; js < ksd; js++ )
4041  {
4042  if ( sData[ js ].meniscus > 0.0 )
4043  total_edits++;
4044  }
4045 
4046  // Count speeds present in this data set
4047  for ( int js = 0; js < rawdat->scanData.size(); js++ )
4048  {
4049  double drpm = rawdat->scanData[ js ].rpm;
4050 
4051  if ( ! drpms.contains( drpm ) )
4052  drpms << drpm;
4053  }
4054 
4055  total_speeds += drpms.size();
4056  }
4057 
4058  // Set flag: are all edits complete?
4059  all_ed_done = ( total_edits == total_speeds );
4060  }
4061 
4062  else
4063  {
4064  all_ed_done = ( range_left != 0 &&
4065  range_right != 0 &&
4066  plateau != 0 &&
4067  baseline != 0 );
4068  }
4069 
4070 DbgLv(1) << "all_ed_done" << all_ed_done;
4071  return all_ed_done;
4072 }
4073 
4074 // Private slot to update disk/db control when dialog changes it
4075 void US_Edit::update_disk_db( bool isDB )
4076 {
4077  if ( isDB )
4078  disk_controls->set_db();
4079  else
4081 }
4082 
4083 // Private slot to show progress text for load-auc
4084 void US_Edit::progress_load( QString progress )
4085 {
4086  le_info->setText( progress );
4087 }
4088 
4089 // Show or hide MWL Controls
4091 {
4092  lb_gaps ->setVisible( !show );
4093  ct_gaps ->setVisible( !show );
4094  le_lxrng ->setVisible( show );
4095  lb_mwlctl ->setVisible( show );
4096  lb_ldelta ->setVisible( show );
4097  ct_ldelta ->setVisible( show );
4098  le_ltrng ->setVisible( show );
4099  lb_lstart ->setVisible( show );
4100  cb_lstart ->setVisible( show );
4101  lb_lend ->setVisible( show );
4102  cb_lend ->setVisible( show );
4103  lb_lplot ->setVisible( show );
4104  cb_lplot ->setVisible( show );
4105  pb_larrow ->setVisible( show );
4106  pb_rarrow ->setVisible( show );
4107  pb_custom ->setVisible( show );
4108  pb_incall ->setVisible( show );
4109 
4110  lo_lrange ->itemAtPosition( 0, 0 )->widget()->setVisible( show );
4111  lo_lrange ->itemAtPosition( 0, 1 )->widget()->setVisible( show );
4112  lo_custom ->itemAtPosition( 0, 0 )->widget()->setVisible( show );
4113  lo_custom ->itemAtPosition( 0, 1 )->widget()->setVisible( show );
4114  lo_radius ->itemAtPosition( 0, 0 )->widget()->setVisible( show );
4115  lo_radius ->itemAtPosition( 0, 1 )->widget()->setVisible( show );
4116  lo_waveln ->itemAtPosition( 0, 0 )->widget()->setVisible( show );
4117  lo_waveln ->itemAtPosition( 0, 1 )->widget()->setVisible( show );
4118  lo_writemwl->itemAtPosition( 0, 0 )->widget()->setVisible( show );
4119  lo_writemwl->itemAtPosition( 0, 1 )->widget()->setVisible( show );
4120 
4121  adjustSize();
4122 }
4123 
4124 // Connect or disconnect MWL Controls
4126 {
4127  if ( conn )
4128  {
4129  connect( rb_lrange, SIGNAL( toggled ( bool ) ),
4130  this, SLOT ( lselect_range_on ( bool ) ) );
4131  connect( rb_custom, SIGNAL( toggled ( bool ) ),
4132  this, SLOT ( lselect_custom_on ( bool ) ) );
4133  connect( ct_ldelta, SIGNAL( valueChanged ( double ) ),
4134  this, SLOT ( ldelta_value ( double ) ) );
4135  connect( cb_lstart, SIGNAL( currentIndexChanged( int ) ),
4136  this, SLOT ( lambda_start_value ( int ) ) );
4137  connect( cb_lend, SIGNAL( currentIndexChanged( int ) ),
4138  this, SLOT ( lambda_end_value ( int ) ) );
4139  connect( rb_radius, SIGNAL( toggled ( bool ) ),
4140  this, SLOT ( xaxis_radius_on ( bool ) ) );
4141  connect( rb_waveln, SIGNAL( toggled ( bool ) ),
4142  this, SLOT ( xaxis_waveln_on ( bool ) ) );
4143  connect( pb_custom, SIGNAL( clicked ( ) ),
4144  this, SLOT ( lambda_custom_list ( ) ) );
4145  connect( pb_incall, SIGNAL( clicked ( ) ),
4146  this, SLOT ( lambda_include_all ( ) ) );
4147  connect( cb_lplot, SIGNAL( currentIndexChanged( int ) ),
4148  this, SLOT ( lambda_plot_value ( int ) ) );
4149  connect( pb_larrow, SIGNAL( clicked ( ) ),
4150  this, SLOT ( lambda_plot_prev ( ) ) );
4151  connect( pb_rarrow, SIGNAL( clicked ( ) ),
4152  this, SLOT ( lambda_plot_next ( ) ) );
4153  }
4154 
4155  else
4156  {
4157  rb_lrange->disconnect();
4158  rb_custom->disconnect();
4159  ct_ldelta->disconnect();
4160  cb_lstart->disconnect();
4161  cb_lend ->disconnect();
4162  rb_radius->disconnect();
4163  rb_waveln->disconnect();
4164  pb_custom->disconnect();
4165  pb_incall->disconnect();
4166  cb_lplot ->disconnect();
4167  pb_larrow->disconnect();
4168  pb_rarrow->disconnect();
4169  }
4170 }
4171 
4172 // Lambda selection has been changed to Range or Custom
4173 void US_Edit::lselect_range_on( bool checked )
4174 {
4175 DbgLv(1) << "lselect range checked" << checked;
4176  if ( checked )
4177  {
4178  connect_mwl_ctrls( false );
4179  ct_ldelta->setValue( 1 );
4180  cb_lstart->setCurrentIndex( 0 );
4181  cb_lend ->setCurrentIndex( nwaveln - 1 );
4182  connect_mwl_ctrls( true );
4183 
4185  }
4186 
4187  ct_ldelta ->setEnabled( checked );
4188  cb_lstart ->setEnabled( checked );
4189  cb_lend ->setEnabled( checked );
4190  pb_custom ->setEnabled( !checked );
4191  lsel_range = checked;
4192 }
4193 
4194 // Lambda selection has been changed to Range or Custom
4195 void US_Edit::lselect_custom_on( bool checked )
4196 {
4197 DbgLv(1) << "lselect custom checked" << checked;
4198  if ( checked )
4199  {
4200  connect_mwl_ctrls( false );
4201  ct_ldelta->setValue( 1 );
4202  cb_lstart->setCurrentIndex( 0 );
4203  cb_lend ->setCurrentIndex( nwaveln - 1 );
4204  connect_mwl_ctrls( true );
4205 
4207  }
4208 
4209  ct_ldelta ->setEnabled( !checked );
4210  cb_lstart ->setEnabled( !checked );
4211  cb_lend ->setEnabled( !checked );
4212  pb_custom ->setEnabled( checked );
4213  lsel_range = !checked;
4214 }
4215 
4216 // Lambda Delta has changed
4217 void US_Edit::ldelta_value( double value )
4218 {
4219 DbgLv(1) << "ldelta_value value" << value;
4220  dlambda = (int)value;
4221 
4223 }
4224 
4225 // Lambda Start has changed
4227 {
4228  slambda = cb_lstart->itemText( value ).toInt();
4229 DbgLv(1) << "lambda_start_value value" << value << slambda;
4230 
4232 }
4233 
4234 // Lambda End has changed
4235 void US_Edit::lambda_end_value( int value )
4236 {
4237  elambda = cb_lend ->itemText( value ).toInt();
4238 DbgLv(1) << "lambda_end_value value" << value << elambda;
4239 
4241 }
4242 
4243 // Adjust the plot wavelengths list, after a lambda range change
4245 {
4246  dlambda = (int)ct_ldelta->value();
4247  slambda = cb_lstart->currentText().toInt();
4248  elambda = cb_lend ->currentText().toInt();
4249  int plambd = cb_lplot ->currentText().toInt();
4250  int strtx = rawi_wvlns.indexOf( slambda );
4251  int endx = rawi_wvlns.indexOf( elambda ) + 1;
4252  int plotx = cb_lplot ->currentIndex();
4253 DbgLv(1) << "rpl: dl sl el px" << dlambda << slambda << elambda << plotx
4254  << "sx ex nr" << strtx << endx << rawc_wvlns.size();
4255 DbgLv(1) << "rpl: trx" << triple_index << cb_triple->currentIndex();
4256 DbgLv(1) << "rpl: rcw 0 1 m n" << rawc_wvlns[0] << rawc_wvlns[1]
4257  << rawc_wvlns[nwaveln-2] << rawc_wvlns[nwaveln-1];
4258  expc_wvlns.clear();
4259  expi_wvlns.clear();
4260 
4261  for ( int ii = strtx; ii < endx; ii += dlambda )
4262  { // Accumulate new list of export lambdas by looking at all raw lambas
4263  QString clam = rawc_wvlns[ ii ];
4264  int rlam = clam.toInt(); // Current raw input lambda
4265  expc_wvlns << clam;
4266  expi_wvlns << rlam;
4267  }
4268 
4269  nwavelo = expi_wvlns.size();
4270  plotx = qMax( 0, expi_wvlns.indexOf( plambd ) );
4271  plotx = ( plotx < nwavelo ) ? plotx : ( nwavelo / 2 );
4272 DbgLv(1) << "rpl: nwavelo plotx" << nwavelo << plotx;
4273 DbgLv(1) << "rpl: pl1 pln" << expi_wvlns[0] << expi_wvlns[nwavelo-1];
4274 
4275  if ( xaxis_radius )
4276  { // If x-axis is radius, reset wavelength-to-plot list
4277  cb_lplot->disconnect();
4278  cb_lplot->clear();
4279  cb_lplot->addItems( expc_wvlns );
4280  connect( cb_lplot, SIGNAL( currentIndexChanged( int ) ),
4281  this, SLOT ( lambda_plot_value ( int ) ) );
4282  cb_lplot->setCurrentIndex( plotx );
4283  }
4284 
4285  // Report export lambda range
4286  le_lxrng ->setText( tr( "%1 MWL exports: %2 %3 to %4," )
4287  .arg( nwavelo ).arg( chlamb ).arg( slambda ).arg( elambda )
4288  + ( lsel_range ? tr( " raw index increment %1." ).arg( dlambda )
4289  : tr( " from custom selections." ) ) );
4290 
4291  mwl_data.set_lambdas( expi_wvlns, triple_index );
4292 DbgLv(1) << "rpl: set_lambdas() complete. trx" << triple_index;
4293 
4294  reset_outData();
4295 DbgLv(1) << "rpl: reset_outData() complete";
4296 }
4297 
4298 // X-axis has been changed to Radius or Wavelength
4299 void US_Edit::xaxis_radius_on( bool checked )
4300 {
4301 DbgLv(1) << "xaxis_radius_on checked" << checked;
4302  if ( checked )
4303  {
4304  xaxis_radius = true;
4305  lb_lplot->setText( tr( "Plot (W nm):" ) );
4306 
4307  cb_lplot->disconnect();
4308  cb_lplot->clear();
4309  cb_lplot->addItems( expc_wvlns );
4310  connect( cb_lplot, SIGNAL( currentIndexChanged( int ) ),
4311  this, SLOT ( lambda_plot_value ( int ) ) );
4312  cb_lplot->setCurrentIndex( expc_wvlns.size() / 2 );
4313  }
4314 }
4315 
4316 // X-axis has been changed to Radius or Wavelength
4317 void US_Edit::xaxis_waveln_on( bool checked )
4318 {
4319 DbgLv(1) << "xaxis_waveln_on checked" << checked;
4320  if ( checked )
4321  {
4322  xaxis_radius = false;
4323  lb_lplot->setText( tr( "Plot (R cm):" ) );
4324 
4325  cb_lplot->disconnect();
4326  cb_lplot->clear();
4327  cb_lplot->addItems( expc_radii );
4328  connect( cb_lplot, SIGNAL( currentIndexChanged( int ) ),
4329  this, SLOT ( lambda_plot_value ( int ) ) );
4330  cb_lplot->setCurrentIndex( expc_radii.size() / 2 );
4331  }
4332 }
4333 
4334 // Plot Lambda/Radius value has changed
4336 {
4337  if ( value < 0 ) return;
4338 
4339  double menissv = meniscus;
4340  plotndx = value;
4341 
4342  if ( ! xaxis_radius )
4343  { // If plotting radius records, go straight to plotting
4344  plot_mwl();
4345  return;
4346  }
4347 
4348  // If plotting wavelength records, check need to re-do/un-do edits
4349  QString swavl = cb_lplot ->itemText( plotndx );
4350  QString triple = cb_triple->currentText() + " / " + swavl;
4351  int idax = triples.indexOf( triple );
4352  plotrec = swavl.toInt();
4353 DbgLv(1) << "lambda_plot_value value" << value << plotrec;
4354  QString fname = ( menissv != 0.0 ) ? editFnames[ idax ] : "none";
4355 
4356 
4357  if ( fname == "none" )
4358  { // New wavelength has no edit: turn off edits
4359  set_meniscus();
4360  }
4361 
4362  else if ( fname != "same" )
4363  { // New wavelength has its own edit: apply it
4364  US_DataIO::EditValues parameters;
4365 
4366  US_DataIO::readEdits( workingDir + fname, parameters );
4367 
4368  apply_edits( parameters );
4369  }
4370 
4371  else if ( step != MENISCUS )
4372  { // New wavelength has same edit as others in channel: make sure applied
4373  }
4374 
4375  plot_mwl();
4376 }
4377 
4378 // Plot-previous has been clicked
4380 {
4381 DbgLv(1) << "lambda_plot_prev clicked";
4382  plotndx--;
4383 
4384  if ( plotndx <= 0 )
4385  {
4386  plotndx = 0;
4387  pb_larrow->setEnabled( false );
4388  }
4389 
4390  pb_rarrow->setEnabled ( true );
4391  cb_lplot ->setCurrentIndex( plotndx );
4392 }
4393 
4394 // Plot-next has been clicked
4396 {
4397 DbgLv(1) << "lambda_plot_next clicked";
4398  plotndx++;
4399 
4400  int lstx = xaxis_radius ? ( expc_wvlns.size() - 1 )
4401  : ( expc_radii.size() - 1 );
4402 
4403  if ( plotndx >= lstx )
4404  {
4405  plotndx = lstx;
4406  pb_rarrow->setEnabled( false );
4407  }
4408 
4409  pb_larrow->setEnabled ( true );
4410  cb_lplot ->setCurrentIndex( plotndx );
4411 }
4412 
4413 // Custom Lambdas has been clicked
4415 {
4416 DbgLv(1) << "lambda_custom_list clicked";
4417  lambdas_by_cell();
4418 
4419  US_SelectLambdas* sel_lambd = new US_SelectLambdas( rawi_wvlns );
4420 
4421  connect( sel_lambd, SIGNAL( new_lambda_list( QVector< int > ) ),
4422  this, SLOT ( lambda_new_list( QVector< int > ) ) );
4423 
4424  if ( sel_lambd->exec() == QDialog::Accepted )
4425  {
4426 DbgLv(1) << " lambda_custom_list ACCEPTED";
4427  int plotx = cb_lplot ->currentIndex();
4428  plotx = ( plotx < nwavelo ) ? plotx : ( nwavelo / 2 );
4429 
4430  if ( xaxis_radius )
4431  { // If x-axis is radius, reset wavelength-to-plot list
4432  cb_lplot->disconnect();
4433  cb_lplot->clear();
4434  cb_lplot->addItems( expc_wvlns );
4435  connect( cb_lplot, SIGNAL( currentIndexChanged( int ) ),
4436  this, SLOT ( lambda_plot_value ( int ) ) );
4437  cb_lplot->setCurrentIndex( plotx );
4438  }
4439 
4440  // Report export lambda range
4441  le_lxrng ->setText( tr( "%1 MWL exports: %2 %3 to %4,"
4442  " from custom selections." )
4443  .arg( nwavelo ).arg( chlamb ).arg( slambda ).arg( elambda ) );
4444  }
4445 }
4446 
4447 // Custom Lambdas have been specified
4448 void US_Edit::lambda_new_list( QVector< int > newlams )
4449 {
4450  nwavelo = newlams.count();
4451  expi_wvlns = newlams;
4452  slambda = expi_wvlns[ 0 ];
4453  elambda = expi_wvlns[ nwavelo - 1 ];
4454  expc_wvlns.clear();
4455 DbgLv(1) << "EDT:lnl: nnssee" << nwavelo << expi_wvlns.size() << slambda
4456  << newlams[0] << elambda << newlams[nwavelo-1];
4457 
4458  for ( int ii = 0; ii < nwavelo; ii++ )
4459  expc_wvlns << QString::number( expi_wvlns[ ii ] );
4460 
4461  connect_mwl_ctrls( false );
4462  cb_lplot ->clear();
4463  cb_lplot ->addItems( expc_wvlns );
4464  int strtx = rawi_wvlns.indexOf( slambda );
4465  int endx = rawi_wvlns.indexOf( elambda );
4466  cb_lstart->setCurrentIndex( strtx );
4467  cb_lend ->setCurrentIndex( endx );
4468  cb_lplot ->setCurrentIndex( nwavelo / 2 );
4469  connect_mwl_ctrls( true );
4470 }
4471 
4472 // Include-all-lambda has been clicked
4474 {
4475 DbgLv(1) << "lambda_include_all clicked";
4476  lambdas_by_cell();
4477 
4478  nwavelo = nwaveln;
4481  connect_mwl_ctrls( false );
4482  ct_ldelta->setValue( 1 );
4483  cb_lstart->setCurrentIndex( 0 );
4484  cb_lend ->setCurrentIndex( nwaveln - 1 );
4485  connect_mwl_ctrls( true );
4486 
4488 }
4489 
4490 // OD-limit-on-radii has changed
4491 void US_Edit::od_radius_limit( double value )
4492 {
4493 DbgLv(1) << "od_radius_limit value" << value;
4494  odlimit = value;
4495 
4496  plot_mwl();
4497 
4499  pb_write ->setEnabled( all_edits );
4500  ck_writemwl->setEnabled( all_edits && isMwl );
4501  changes_made = true;
4502 }
4503 
4504 // Write edit to all wavelengths of the current cell/channel
4506 {
4507  QString saved_info = le_info->text();
4508  QString str;
4509  if ( ! isMwl )
4510  {
4511  QMessageBox::warning( this,
4512  tr( "Invalid Selection" ),
4513  tr( "The \"Save to all Wavelengths\" button is only valid\n"
4514  "for MultiWavelength data. No Save will be performed." ) );
4515  return;
4516  }
4517 
4518  meniscus = le_meniscus->text().toDouble();
4519  baseline = data.xvalues[ data.xindex( range_left ) + 5 ];
4520 
4521  if ( expIsEquil )
4522  { // Equilibrium: set baseline,plateau as flag that those are "done"
4523  int jsd = sd_offs[ triple_index ];
4524  meniscus = sData[ jsd ].meniscus;
4525  range_left = sData[ jsd ].dataLeft;
4526  range_right = sData[ jsd ].dataRight;
4527  baseline = range_left;
4528  plateau = range_right;
4529  }
4530 
4531  // Check if complete
4532  if ( meniscus == 0.0 )
4533  str = tr( "meniscus" );
4534  else if ( dataType == "IP" && ( airGap_left == 0.0 || airGap_right == 9.0 ) )
4535  str = tr( "air gap" );
4536  else if ( range_left == 0.0 || range_right == 9.0 )
4537  str = tr( "data range" );
4538  else if ( plateau == 0.0 )
4539  str = tr( "plateau" );
4540  else if ( baseline == 0.0 )
4541  str = tr( "baseline" );
4542 
4543  if ( ! str.isEmpty() )
4544  {
4545  QMessageBox::information( this,
4546  tr( "Data missing" ),
4547  tr( "You must define the " ) + str +
4548  tr( " before writing the edit profile." ) );
4549  return;
4550  }
4551 
4552  QString sufx = "";
4553 
4554  // Ask for editLabel if not yet defined
4555  while ( editLabel.isEmpty() )
4556  {
4557  QString now = QDateTime::currentDateTime()
4558  .toUTC().toString( "yyMMddhhmm" );
4559 
4560  bool ok;
4561  QString msg = tr( "The base Edit Label for this edit session is <b>" )
4562  + now + "</b> .<br/>"
4563  + tr( "You may add an optional suffix to further distinquish<br/>"
4564  "the Edit Label. Use alphanumeric characters, underscores,<br/>"
4565  "or hyphens (no spaces). Enter 0 to 10 suffix characters." );
4566  sufx = QInputDialog::getText( this,
4567  tr( "Create a unique session Edit Label" ),
4568  msg,
4569  QLineEdit::Normal,
4570  sufx,
4571  &ok );
4572 
4573  if ( ! ok ) return;
4574 
4575  sufx.remove( QRegExp( "[^\\w\\d_-]" ) );
4576  editLabel = now + sufx;
4577 
4578  if ( editLabel.length() > 20 )
4579  {
4580  QMessageBox::critical( this,
4581  tr( "Text length error" ),
4582  tr( "You entered %1 characters for the Edit Label suffix.\n"
4583  "Re-enter, limiting length to 10 characters." )
4584  .arg( sufx.length() ) );
4585  editLabel.clear();
4586  sufx = sufx.left( 10 );
4587  }
4588  }
4589 
4590  QVector< int > oldi_wvlns;
4591  int kwavelo = mwl_data.lambdas( oldi_wvlns );
4592  int nwavelo = expi_wvlns.count();
4593  int wvx;
4594  bool chg_lamb = ( kwavelo != nwavelo );
4595 
4596  if ( ! chg_lamb )
4597  { // If no change in number of wavelengths, check actual lists
4598  for ( wvx = 0; wvx < nwavelo; wvx++ )
4599  {
4600  if ( oldi_wvlns[ wvx ] != expi_wvlns[ wvx ] )
4601  { // There is a difference in the lists: mark as such
4602  chg_lamb = true;
4603  break;
4604  }
4605  }
4606  }
4607 
4608  if ( chg_lamb )
4609  { // If wavelengths have changed, save new list and rebuild some vectors
4610  mwl_data.set_lambdas( expi_wvlns ); // Save new lambdas for channel
4611 
4612  reset_outData();
4613  }
4614 
4615  QString celchn = celchns.at( triple_index );
4616  QString scell = celchn.section( "/", 0, 0 ).simplified();
4617  QString schan = celchn.section( "/", 1, 1 ).simplified();
4618  QString tripbase = scell + " / " + schan + " / ";
4619  int idax = triples.indexOf( tripbase + expc_wvlns[ 0 ] );
4620  int odax = index_data( 0 );
4621 DbgLv(1) << "EDT:WrMwl: dax celchn" << odax << celchn;
4622 
4623  QString filebase = files[ idax ].section( ".", 0, -6 )
4624  + "." + editLabel + "."
4625  + files[ idax ].section( ".", -5, -5 )
4626  + "." + scell + "." + schan + ".";
4627  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
4628 
4629  // Loop to output a file/db-record for each wavelength of the cell/channel
4630 
4631 DbgLv(1) << "EDT:WrMwl: files,wvlns.size" << files.size() << expc_wvlns.size();
4632  for ( wvx = 0; wvx < expc_wvlns.size(); wvx++ )
4633  {
4634  QString swavl = expc_wvlns[ wvx ];
4635  QString triple = tripbase + swavl;
4636  QString filename = filebase + swavl + ".xml";
4637  idax = triples.indexOf( triple );
4638  odax = index_data( wvx );
4639 DbgLv(1) << "EDT:WrMwl: wvx triple" << wvx << triple << "filename" << filename;
4640 
4641 DbgLv(1) << "EDT:WrMwl: idax,editGUIDs.size" << idax << editGUIDs.size();
4642  QString editGUID = editGUIDs[ idax ];
4643 
4644  if ( editGUID.isEmpty() )
4645  {
4646  editGUID = US_Util::new_guid();
4647  editGUIDs.replace( idax, editGUID );
4648  }
4649 DbgLv(1) << "EDT:WrMwl: editGUID" << editGUID;
4650 
4651 DbgLv(1) << "EDT:WrMwl: odax,outData.size" << odax << outData.size();
4652  QString rawGUID = US_Util::uuid_unparse(
4653  (unsigned char*)outData[ odax ]->rawGUID );
4654 DbgLv(1) << "EDT:WrMwl: rawGUID" << rawGUID;
4655 
4656  // Output the edit XML file
4657  le_info->setText( tr( "Writing " ) + filename + " ..." );
4658  qApp->processEvents();
4659  int wrstat = write_xml_file( filename, triple, editGUID, rawGUID );
4660 DbgLv(1) << "EDT:WrMwl: write_xml_file stat" << wrstat;
4661 
4662  if ( wrstat != 0 )
4663  return;
4664  else
4665  editFnames[ idax ] = filename;
4666 
4667  if ( disk_controls->db() )
4668  {
4669  if ( dbP == NULL )
4670  {
4671  US_Passwd pw;
4672  dbP = new US_DB2( pw.getPasswd() );
4673  if ( dbP == NULL || dbP->lastErrno() != US_DB2::OK )
4674  {
4675  QMessageBox::warning( this, tr( "Connection Problem" ),
4676  tr( "Could not connect to database \n" ) + dbP->lastError() );
4677  return;
4678  }
4679  }
4680 
4681  QString editID = editIDs[ idax ];
4682 
4683  // Output the edit database record
4684  wrstat = write_edit_db( dbP, filename, editGUID, editID, rawGUID );
4685 DbgLv(1) << "EDT:WrMwl: dax fname" << idax << filename << "wrstat" << wrstat;
4686 
4687  if ( wrstat != 0 )
4688  return;
4689  } // END: DB output
4690  } // END: wavelength-in-cellchannel loop
4691 
4692  QApplication::restoreOverrideCursor();
4693  changes_made = false;
4694  pb_write ->setEnabled( false );
4695  ck_writemwl ->setEnabled( false );
4696  le_info->setText( saved_info );
4697  qApp->processEvents();
4698 DbgLv(1) << "EDT:WrMwl: DONE";
4699 }
4700 
4701 // Write edit xml file
4702 int US_Edit::write_xml_file( QString& fname, QString& triple,
4703  QString& editGUID, QString& rawGUID )
4704 {
4705  QFile efo( workingDir + fname );
4706 
4707  if ( ! efo.open( QFile::WriteOnly | QFile::Text ) )
4708  {
4709  QMessageBox::information( this,
4710  tr( "File write error" ),
4711  tr( "Could not open the file\n" ) + workingDir + fname
4712  + tr( "\n for writing. Check your permissions." ) );
4713  return 1;
4714  }
4715 
4716 DbgLv(1) << "EDT:WrXml: IN: fname,triple,editGUID,rawGUID"
4717  << fname << triple << editGUID << rawGUID;
4718  QXmlStreamWriter xml( &efo );
4719 
4720  xml.setAutoFormatting( true );
4721  xml.writeStartDocument();
4722  xml.writeDTD ( "<!DOCTYPE UltraScanEdits>" );
4723  xml.writeStartElement( "experiment" );
4724  xml.writeAttribute ( "type", expType );
4725 
4726  // Write identification
4727  xml.writeStartElement( "identification" );
4728 
4729  xml.writeStartElement( "runid" );
4730  xml.writeAttribute ( "value", runID );
4731  xml.writeEndElement ();
4732 
4733  xml.writeStartElement( "editGUID" );
4734  xml.writeAttribute ( "value", editGUID );
4735  xml.writeEndElement ();
4736 
4737  xml.writeStartElement( "rawDataGUID" );
4738  xml.writeAttribute ( "value", rawGUID );
4739  xml.writeEndElement ();
4740 
4741  xml.writeEndElement (); // identification
4742 
4743  QStringList parts = triple.contains( " / " ) ?
4744  triple.split( " / " ) :
4745  triple.split( "." );
4746 DbgLv(1) << "EDT:WrXml: parts.size" << parts.size();
4747 
4748  QString cell = parts[ 0 ];
4749  QString channel = parts[ 1 ];
4750  QString waveln = parts[ 2 ];
4751 
4752 DbgLv(1) << "EDT:WrXml: waveln" << waveln;
4753 
4754  xml.writeStartElement( "run" );
4755  xml.writeAttribute ( "cell", cell );
4756  xml.writeAttribute ( "channel", channel );
4757  xml.writeAttribute ( "wavelength", waveln );
4758 
4759  // Write excluded scans
4760  if ( data.scanData.size() > includes.size() )
4761  {
4762  xml.writeStartElement( "excludes" );
4763 
4764  for ( int ii = 0; ii < data.scanData.size(); ii++ )
4765  {
4766  if ( ! includes.contains( ii ) )
4767  {
4768  xml.writeStartElement( "exclude" );
4769  xml.writeAttribute ( "scan", QString::number( ii ) );
4770  xml.writeEndElement ();
4771  }
4772  }
4773 
4774  xml.writeEndElement (); // excludes
4775  }
4776 
4777  // Write edits
4778  if ( ! changed_points.isEmpty() )
4779  {
4780  xml.writeStartElement( "edited" );
4781 
4782  for ( int ii = 0; ii < changed_points.size(); ii++ )
4783  {
4784  Edits* e = &changed_points[ ii ];
4785 
4786  for ( int jj = 0; jj < e->changes.size(); jj++ )
4787  {
4788  xml.writeStartElement( "edit" );
4789  xml.writeAttribute ( "scan", QString::number( e->scan ) );
4790  xml.writeAttribute ( "radius",
4791  QString::number( e->changes[ jj ].x(), 'f', 4 ) );
4792  xml.writeAttribute ( "value",
4793  QString::number( e->changes[ jj ].y(), 'f', 4 ) );
4794  xml.writeEndElement ();
4795  }
4796  }
4797 
4798  xml.writeEndElement (); // edited
4799  }
4800 
4801  // Write meniscus, range, plateau, baseline, odlimit
4802  xml.writeStartElement( "parameters" );
4803 
4804  if ( ! expIsEquil )
4805  { // non-Equilibrium
4806  xml.writeStartElement( "meniscus" );
4807  xml.writeAttribute ( "radius",
4808  QString::number( meniscus, 'f', 4 ) );
4809  xml.writeEndElement ();
4810 
4811  if ( dataType == "IP" )
4812  {
4813  xml.writeStartElement( "air_gap" );
4814  xml.writeAttribute ( "left",
4815  QString::number( airGap_left, 'f', 4 ) );
4816  xml.writeAttribute ( "right",
4817  QString::number( airGap_right, 'f', 4 ) );
4818  xml.writeAttribute ( "tolerance",
4819  QString::number( ct_gaps->value(), 'f', 4 ) );
4820  xml.writeEndElement ();
4821  }
4822 
4823  xml.writeStartElement( "data_range" );
4824  xml.writeAttribute ( "left",
4825  QString::number( range_left, 'f', 4 ) );
4826  xml.writeAttribute ( "right",
4827  QString::number( range_right, 'f', 4 ) );
4828  xml.writeEndElement ();
4829 
4830  xml.writeStartElement( "plateau" );
4831  xml.writeAttribute ( "radius",
4832  QString::number( plateau, 'f', 4 ) );
4833  xml.writeEndElement ();
4834 
4835  xml.writeStartElement( "baseline" );
4836  xml.writeAttribute ( "radius",
4837  QString::number( baseline, 'f', 4 ) );
4838  xml.writeEndElement ();
4839 
4840  xml.writeStartElement( "od_limit" );
4841  xml.writeAttribute ( "value",
4842  QString::number( odlimit, 'f', 4 ) );
4843  xml.writeEndElement ();
4844  }
4845 
4846  else
4847  { // Equilibrium
4848  if ( dataType == "IP" )
4849  {
4850  xml.writeStartElement( "air_gap" );
4851  xml.writeAttribute ( "left",
4852  QString::number( airGap_left, 'f', 4 ) );
4853  xml.writeAttribute ( "right",
4854  QString::number( airGap_right, 'f', 4 ) );
4855  xml.writeAttribute ( "tolerance",
4856  QString::number( ct_gaps->value(), 'f', 4 ) );
4857  xml.writeEndElement ();
4858  }
4859 
4860  int jsd = sd_offs[ triple_index ];
4861  int ksd = jsd + sd_knts[ triple_index ];
4862 
4863  for ( int ii = jsd; ii < ksd; ii++ )
4864  {
4865  double speed = sData[ ii ].speed;
4866  int sStart = sData[ ii ].first_scan;
4867  int sCount = sData[ ii ].scan_count;
4868  double meniscus = sData[ ii ].meniscus;
4869  double dataLeft = sData[ ii ].dataLeft;
4870  double dataRight = sData[ ii ].dataRight;
4871 
4872  xml.writeStartElement( "speed" );
4873  xml.writeAttribute ( "value", QString::number( speed ) );
4874  xml.writeAttribute ( "scanStart", QString::number( sStart ) );
4875  xml.writeAttribute ( "scanCount", QString::number( sCount ) );
4876 
4877  xml.writeStartElement( "meniscus" );
4878  xml.writeAttribute ( "radius", QString::number( meniscus, 'f', 4 ) );
4879  xml.writeEndElement (); // meniscus
4880 
4881  xml.writeStartElement( "data_range" );
4882  xml.writeAttribute ( "left", QString::number( dataLeft, 'f', 4 ) );
4883  xml.writeAttribute ( "right", QString::number( dataRight, 'f', 4 ) );
4884  xml.writeEndElement (); // data_range
4885 
4886  xml.writeEndElement (); // speed
4887  }
4888  }
4889 
4890  xml.writeEndElement (); // parameters
4891 
4892  if ( ! pb_residuals->icon().isNull() ||
4893  ! pb_spikes->icon().isNull() ||
4894  invert == -1.0 ||
4895  floatingData )
4896  {
4897  xml.writeStartElement( "operations" );
4898 
4899  // Write RI Noise
4900  if ( ! pb_residuals->icon().isNull() )
4901  {
4902  xml.writeStartElement( "subtract_ri_noise" );
4903  xml.writeAttribute ( "order", QString::number( noise_order ) );
4904  xml.writeEndElement ();
4905  }
4906 
4907  // Write Remove Spikes
4908  if ( ! pb_spikes->icon().isNull() )
4909  {
4910  xml.writeStartElement( "remove_spikes" );
4911  xml.writeEndElement ();
4912  }
4913 
4914  // Write Invert
4915  if ( invert == -1.0 )
4916  {
4917  xml.writeStartElement( "invert" );
4918  xml.writeEndElement ();
4919  }
4920 
4921  // Write indication of floating data
4922  if ( floatingData )
4923  {
4924  xml.writeStartElement( "floating_data" );
4925  xml.writeEndElement ();
4926  }
4927 
4928  xml.writeEndElement (); // operations
4929  }
4930 
4931  xml.writeEndElement (); // run
4932  xml.writeEndElement (); // experiment
4933  xml.writeEndDocument ();
4934 
4935  efo.close();
4936  return 0;
4937 }
4938 
4939 // Write edit database record
4940 int US_Edit::write_edit_db( US_DB2* dbP, QString& fname, QString& editGUID,
4941  QString& editID, QString& rawGUID )
4942 {
4943  int idEdit;
4944 
4945  if ( dbP == NULL )
4946  {
4947  QMessageBox::warning( this, tr( "Connection Problem" ),
4948  tr( "Could not connect to database \n" ) + dbP->lastError() );
4949  return 1;
4950  }
4951 
4952  QStringList query( "get_rawDataID_from_GUID" );
4953  query << rawGUID;
4954  dbP->query( query );
4955 
4956  if ( dbP->lastErrno() != US_DB2::OK )
4957  {
4958  QMessageBox::warning( this,
4959  tr( "AUC Data is not in DB" ),
4960  tr( "Cannot save edit data to the database.\n"
4961  "The associated AUC data is not present." ) );
4962  return 2;
4963  }
4964 
4965  dbP->next();
4966  QString rawDataID = dbP->value( 0 ).toString();
4967 
4968 
4969  // Save edit file to DB
4970  query.clear();
4971 
4972  if ( editID.isEmpty() )
4973  {
4974  query << "new_editedData" << rawDataID << editGUID << runID
4975  << fname << "";
4976 
4977  dbP->query( query );
4978 
4979  if ( dbP->lastErrno() != US_DB2::OK )
4980  {
4981  QMessageBox::warning( this, tr( "Database Problem" ),
4982  tr( "Could not insert metadata into the database\n" ) +
4983  dbP->lastError() );
4984 
4985  return 3;
4986  }
4987 
4988  idEdit = dbP->lastInsertID();
4989  editID = QString::number( idEdit );
4990  int dax = editGUIDs.indexOf( editGUID );
4991  editIDs.replace( dax, editID );
4992  }
4993 
4994  else
4995  {
4996  query << "update_editedData" << editID << rawDataID << editGUID
4997  << runID << fname << "";
4998  dbP->query( query );
4999 
5000  if ( dbP->lastErrno() != US_DB2::OK )
5001  {
5002  QMessageBox::warning( this, tr( "Database Problem" ),
5003  tr( "Could not update metadata in the database \n" ) +
5004  dbP->lastError() );
5005 
5006  return 4;
5007  }
5008 
5009  idEdit = editID.toInt();
5010  }
5011 
5012  dbP->writeBlobToDB( workingDir + fname, "upload_editData", idEdit );
5013 
5014  if ( dbP->lastErrno() != US_DB2::OK )
5015  {
5016  QMessageBox::warning( this, tr( "Database Problem" ),
5017  tr( "Could not insert edit xml data into database \n" ) +
5018  dbP->lastError() );
5019  return 5;
5020  }
5021 
5022  return 0;
5023 }
5024 
5025 // Return the index in the output data of the current or specified wavelength
5026 int US_Edit::index_data( int wvx )
5027 {
5028  triple_index = cb_triple->currentIndex(); // Triple index
5029  int odatx = triple_index; // Default output data index
5030 
5031  if ( isMwl )
5032  { // For MWL, compute data index from wavelength and triple indexes
5033  if ( wvx < 0 )
5034  { // For the default case, use the current wavelength index
5035  plotndx = cb_lplot->currentIndex();
5036  int iwavl = expi_wvlns[ plotndx ];
5038  odatx = data_index;
5039 DbgLv(1) << "IxDa: dx" << data_index << "plx wavl trx"
5040  << plotndx << iwavl << triple_index;
5041  }
5042 
5043  else
5044  { // Use a specified wavelength index (and do not set internal value)
5045  int iwavl = expi_wvlns[ wvx ];
5046  odatx = mwl_data.data_index( iwavl, triple_index );
5047  }
5048  }
5049 
5050  else // for non-MWL, set data index internal value to triple index
5052 
5053  return odatx;
5054 }
5055 
5056 // Get a list of filenames with Edit Label like a specified file name
5057 int US_Edit::like_edit_files( QString filename, QStringList& editfiles,
5058  US_DB2* dbP )
5059 {
5060  // Determine local-disk files with same edit label and cell/channel
5061  QString filebase = filename.section( ".", 0, -3 );
5062  QStringList filter( filebase + ".*.xml" );
5063  QStringList edfiles = QDir( workingDir ).entryList(
5064  filter, QDir::Files, QDir::Name );
5065  QStringList ldfiles;
5066 
5067  // Pare down the list to those with triples matching loaded files
5068  for ( int ii = 0; ii < edfiles.count(); ii++ )
5069  {
5070  QString fname = edfiles[ ii ];
5071  QString triple = fname.section( ".", -4, -2 ).replace( ".", " / " );
5072 
5073  if ( triples.contains( triple ) )
5074  ldfiles << fname;
5075  }
5076 
5077  int nledits = ldfiles.count();
5078 DbgLv(1) << "LiEdFi: nledits" << ldfiles.count() << filter;
5079 
5080  if ( dbP != NULL )
5081  { // Determine database like files and compare to local
5082  QString invID = QString::number( US_Settings::us_inv_ID() );
5083  QStringList dbfiles;
5084  QStringList dbEdIds;
5085  QStringList dbquery;
5086 // QString rawGUID = US_Util::uuid_unparse( (unsigned char*)data.rawGUID );
5087 
5088  // Get the rawData ID for this data
5089 // dbquery.clear();
5090 // dbquery << "get_rawDataID_from_GUID" << rawGUID;
5091 // dbP->query( dbquery );
5092 // dbP->next();
5093 // QString rawDataID = dbP->value( 0 ).toString();
5094 //DbgLv(1) << "LiEdFi: rawDataID" << rawDataID;
5095 
5096  // Get the filenames and edit IDs for like-named files in the DB
5097  dbquery.clear();
5098 // dbquery << "get_editedDataIDs" << rawDataID;
5099  dbquery << "all_editedDataIDs" << invID;
5100  dbP->query( dbquery );
5101 
5102  while ( dbP->next() )
5103  { // Accumulate filenames and editIDs from the database
5104  QString idData = dbP->value( 0 ).toString();
5105  QString efname = dbP->value( 2 ).toString()
5106  .section( "/", -1, -1 );
5107  QString triple = efname.section( ".", -4, -2 )
5108  .replace( ".", " / " );
5109 //DbgLv(1) << "LiEdFi: db0,2" << idData << efname << "fbase" << filebase;
5110 
5111  // If the file name has a like edit label, has the same cell/channel,
5112  // and has triple matching a loaded file, save it.
5113  if ( efname.startsWith( filebase ) && triples.contains( triple ) )
5114  {
5115  dbfiles << efname;
5116  dbEdIds << idData;
5117 DbgLv(1) << "LiEdFi: id fn dbfsiz" << idData << efname << dbfiles.count();
5118  }
5119  }
5120 
5121  int nlocals = ldfiles.count();
5122  nledits = dbfiles.count();
5123 DbgLv(1) << "LiEdFi: nlocals nledits" << nlocals << nledits;
5124 
5125  if ( nledits != nlocals )
5126  { // DB records are not matched locally, so download from DB
5127  if ( nlocals == 0 )
5128  QDir().mkpath( workingDir );
5129 
5130  dbfiles.sort();
5131 
5132  for ( int ii = 0; ii < dbfiles.count(); ii++ )
5133  { // Download each DB record to a local file
5134  QString fname = workingDir + dbfiles[ ii ];
5135  int dataID = dbEdIds[ ii ].toInt();
5136 
5137  dbP->readBlobFromDB( fname, "download_editData", dataID );
5138  }
5139 
5140  ldfiles = dbfiles;
5141  }
5142  }
5143 
5144  editfiles = ldfiles;
5145  nledits = editfiles.count();
5146 
5147  if ( nledits == 0 )
5148  { // No files (should not happen): return at least the specified file name
5149  editfiles << filename;
5150  nledits = 1;
5151  }
5152 
5153  else if ( nledits > 1 )
5154  { // If multiple files, sort them
5155  editfiles.sort();
5156  }
5157 DbgLv(1) << "LiEdFi: nle fn0" << nledits << editfiles[0];
5158 
5159  return nledits;
5160 }
5161 
5162 // Apply edits to the current triple data
5164 {
5165  int status = 0;
5166 
5167  // Apply the edits with specified parameters
5168  QString wkstr;
5169 
5170  meniscus = parameters.meniscus;
5171  range_left = parameters.rangeLeft;
5172  range_right = parameters.rangeRight;
5173  plateau = parameters.plateau;
5174  baseline = parameters.baseline;
5175  odlimit = parameters.ODlimit;
5176 
5177  le_meniscus->setText( wkstr.sprintf( "%.3f", meniscus ) );
5178  pb_meniscus->setIcon( check );
5179  pb_meniscus->setEnabled( true );
5180 
5181  airGap_left = parameters.airGapLeft;
5182  airGap_right = parameters.airGapRight;
5183 
5184  if ( dataType == "IP" )
5185  {
5186  US_DataIO::adjust_interference( data, parameters );
5187  US_DataIO::calc_integral ( data, parameters );
5188  le_airGap->setText( wkstr.sprintf( "%.3f - %.3f",
5189  airGap_left, airGap_right ) );
5190  pb_airGap->setIcon( check );
5191  pb_airGap->setEnabled( true );
5192  }
5193 
5194  le_dataRange->setText( wkstr.sprintf( "%.3f - %.3f",
5195  range_left, range_right ) );
5196  pb_dataRange->setIcon( check );
5197  pb_dataRange->setEnabled( true );
5198 
5199  le_plateau ->setText( wkstr.sprintf( "%.3f", plateau ) );
5200  pb_plateau ->setIcon( check );
5201  pb_plateau ->setEnabled( true );
5202 
5203  US_DataIO::Scan scan = data.scanData.last();
5204  int pt = data.xindex( baseline );
5205  double sum = 0.0;
5206 
5207  // Average the value for +/- 5 points
5208  for ( int jj = pt - 5; jj <= pt + 5; jj++ )
5209  sum += scan.rvalues[ jj ];
5210 
5211  le_baseline->setText( wkstr.sprintf( "%.3f (%.3e)", baseline, sum / 11.0 ) );
5212 
5213  // Invert
5214  invert = parameters.invert;
5215 
5216  if ( invert == -1.0 ) pb_invert->setIcon( check );
5217  else pb_invert->setIcon( QIcon() );
5218 
5219  // Excluded scans
5220  init_includes();
5221  reset_excludes(); // Zero exclude combo boxes
5222  qSort( parameters.excludes );
5223 
5224  for ( int ii = parameters.excludes.size(); ii > 0; ii-- )
5225  includes.removeAt( parameters.excludes[ ii - 1 ] );
5226 
5227  // Edited points
5228  changed_points.clear();
5229 
5230  for ( int ii = 0; ii < parameters.editedPoints.size(); ii++ )
5231  {
5232  int scan = parameters.editedPoints[ ii ].scan;
5233  int index1 = (int)parameters.editedPoints[ ii ].radius;
5234  double value = parameters.editedPoints[ ii ].value;
5235 
5236  Edits e;
5237  e.scan = scan;
5238  e.changes << QPointF( index1, value );
5239 
5240  changed_points << e;
5241 
5242  data.scanData[ scan ].rvalues[ index1 ] = value;
5243  }
5244 
5245  // Spikes
5246  spikes = parameters.removeSpikes;
5247 
5248  pb_spikes->setIcon( QIcon() );
5249  pb_spikes->setEnabled( true );
5250  if ( spikes ) remove_spikes();
5251 
5252  // Noise
5253  noise_order = parameters.noiseOrder;
5254  if ( noise_order > 0 )
5255  {
5258 
5260  }
5261  else
5262  {
5263  pb_noise ->setIcon( QIcon() );
5264  pb_residuals->setIcon( QIcon() );
5265  pb_residuals->setEnabled( false );
5266  }
5267 
5268  // Floating data
5269  floatingData = parameters.floatingData;
5270  if ( floatingData )
5271  pb_float->setIcon( check );
5272  else
5273  pb_float->setIcon( QIcon() );
5274 
5275  ct_odlim->disconnect();
5276  ct_odlim->setValue( odlimit );
5277  connect( ct_odlim, SIGNAL( valueChanged ( double ) ),
5278  this, SLOT ( od_radius_limit ( double ) ) );
5279 
5280  set_pbColors( NULL );
5281  step = FINISHED;
5282 
5283  return status;
5284 }
5285 
5286 // Reset the output data pointer vector after change in wavelengths
5288 {
5289  if ( ! isMwl ) return;
5290 
5291  outData.clear();
5292  QVector< int > ex_wvlns;
5293  int ccoff = 0;
5294 DbgLv(1) << "rsoD: aDa size" << allData.size() << "ncelchn" << ncelchn;
5295 
5296  for ( int ccx = 0; ccx < ncelchn; ccx++ )
5297  {
5298  lambdas_by_cell( ccx );
5299 
5300  int kwvln = mwl_data.lambdas( ex_wvlns, ccx );
5301 DbgLv(1) << "rsoD: ccx kwv" << ccx << kwvln << ex_wvlns.size()
5302  << "nwv ccoff" << nwaveln << ccoff;
5303 
5304  for ( int wvo = 0; wvo < kwvln; wvo++ )
5305  {
5306  int iwavl = ex_wvlns[ wvo ];
5307  int idatx = ccoff + rawi_wvlns.indexOf( iwavl );
5308 //DbgLv(1) << "rsoD: wvo" << wvo << "wavl datx" << iwavl << idatx;
5309  outData << &allData[ idatx ];
5310  }
5311 
5312  ccoff += nwaveln;
5313 //DbgLv(1) << "rsoD: ccx ccoff" << ccx << ccoff;
5314  }
5315 DbgLv(1) << "rsoD: final ccoff" << ccoff << "aDa size" << allData.size()
5316  << "oDa size" << outData.size();
5317 }
5318 
5319 // Get input wavelengths vector for the current cell
5321 {
5322  int ccx = ( trx < 0 ) ? triple_index : trx;
5323  nwaveln = rawi_wvlns.count();
5324 
5325  if ( lrng_bycell )
5326  {
5327  rawi_wvlns = wavelns_i[ ccx ];
5328  nwaveln = rawi_wvlns.count();
5329  rawc_wvlns.clear();
5330 
5331  for ( int wvx = 0; wvx < nwaveln; wvx++ )
5332  {
5333  rawc_wvlns << QString::number( rawi_wvlns[ wvx ] );
5334  }
5335  }
5336 
5337  return nwaveln;
5338 }
5339 
5340 // Return the radius value at the radius index nearest a given radius
5341 double US_Edit::radius_indexed( const double radi )
5342 {
5343  return data.radius( data.xindex( radi ) );
5344 }
5345