UltraScan III
us_mwl_spectra.cpp
Go to the documentation of this file.
1 #include <QApplication>
3 
4 #include "us_mwl_spectra.h"
5 #include "us_mwls_pltctl.h"
6 #include "us_license_t.h"
7 #include "us_license.h"
8 #include "us_select_runs.h"
9 #include "us_util.h"
10 #include "us_settings.h"
11 #include "us_gui_settings.h"
12 #include "us_plot.h"
13 #include "us_math2.h"
14 #include "us_db2.h"
15 #include "us_passwd.h"
16 #include "us_investigator.h"
17 #include "us_constants.h"
18 #include "us_report.h"
19 #include "us_gui_util.h"
20 #include "us_util.h"
21 #include "us_sleep.h"
22 #include "us_editor.h"
23 #include "us_images.h"
24 
25 #ifdef WIN32
26 #include <float.h>
27 #define isnan _isnan
28 #endif
29 
30 #ifndef DbgLv
31 #define DbgLv(a) if(dbg_level>=a)qDebug()
32 #endif
33 
34 int main( int argc, char* argv[] )
35 {
36  QApplication application( argc, argv );
37 
38  #include "main1.inc"
39 
40  // License is OK. Start up.
41 
42  US_MwlSpectra ww;
43  ww.show();
44  return application.exec();
45 }
46 
48 {
49  const QChar chlamb( 955 );
50 
51  setWindowTitle( tr( "Multi-Wavelength S Spectra Viewer" ) );
52  setPalette( US_GuiSettings::frameColor() );
53 
54  QGridLayout* settings = new QGridLayout;
55 
56  nsmooth = 3;
58  mfilter = "";
59  p3d_ctld = NULL;
60  p3d_pltw = NULL;
61  runID = "";
63  QFontMetrics fmet( sfont );
64  int fwid = fmet.maxWidth();
65  int lwid = fwid * 3;
66 
67  // Disk/DB controls
70 
71  // Load controls
72  QLabel* lb_run = us_banner ( tr( "Load the Models" ) );
73  pb_prefilt = us_pushbutton( tr( "Select PreFilter" ) );
74  pb_loaddis = us_pushbutton( tr( "Load Distributions" ) );
75  pb_reset = us_pushbutton( tr( "Reset Data" ) );
76  pb_details = us_pushbutton( tr( "Data Details" ), false );
77 
78  int rhgt = pb_prefilt->height();
79  QLabel* lb_smooth = us_label( tr( "%1 Gaussian Smooth Points:" )
80  .arg( chlamb),
81  -1 );
82  ct_smooth = us_counter( 1, 1, 100, 1 );
83  ct_smooth->setStep( 1.0 );
84  ct_smooth->setFont( sfont );
85  ct_smooth->setMinimumWidth( fwid );
86  ct_smooth->resize( rhgt, lwid );
87  ct_smooth->setValue( nsmooth );
88 
89  // Plot Range controls
90  QLabel* lb_prcntls = us_banner( tr( "Plot Range Controls" ) );
91  QLabel* lb_sstart = us_label( tr( "S Start:" ), -1 );
93  QLabel* lb_send = us_label( tr( "S End:" ), -1 );
94  cb_send = us_comboBox();
95  QLabel* lb_lstart = us_label( tr( "%1 Start:" ).arg( chlamb ), -1 );
97  QLabel* lb_lend = us_label( tr( "%1 End:" ).arg( chlamb ), -1 );
98  cb_lend = us_comboBox();
99  lb_pltrec = us_label( tr( "S x 10^13:" ) );
101  cb_pltrec ->addItem( "1.00" );
102  cb_pltrec ->addItem( "1.10" );
103 
104  pb_prev = us_pushbutton( tr( "Previous" ) );
105  pb_next = us_pushbutton( tr( "Next" ) );
108 
109  // Advanced Plotting controls
110  QLabel* lb_advplot = us_banner( tr( "Advanced Plotting Control" ) );
111  pb_plot2d = us_pushbutton( tr( "Refresh 2D Plot" ) );
112  pb_movie2d = us_pushbutton( tr( "Show 2D Movie" ) );
113  pb_plot3d = us_pushbutton( tr( "Plot 3D" ) );
114  pb_svplot = us_pushbutton( tr( "Save Plot(s)" ) );
115  pb_svmovie = us_pushbutton( tr( "Save Movie" ) );
116  QLabel* lb_delay = us_label( tr( "Delay" ) );
117  ct_delay = us_counter( 1, 0.1, 10.0, 0.1 );
118  ct_delay ->setStep( 0.1 );
119  ct_delay ->setFont( sfont );
120  ct_delay ->setMinimumWidth( fwid );
121  ct_delay ->resize( rhgt, lwid );
122  ct_delay ->setValue( 0.5 );
123 
124  // Status and standard pushbuttons
125  QLabel* lb_status = us_banner( tr( "Status" ) );
126  le_status = us_lineedit( tr( "(no data loaded)" ), -1, true );
127  QPalette stpal;
128  stpal.setColor( QPalette::Text, Qt::white );
129  stpal.setColor( QPalette::Base, Qt::blue );
130  le_status->setPalette( stpal );
131 
132  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
133  QPushButton* pb_close = us_pushbutton( tr( "Close" ) );
134 
135  // Signals and Slots
136  connect( pb_prefilt, SIGNAL( clicked() ),
137  this, SLOT ( select_prefilt() ) );
138  connect( pb_loaddis, SIGNAL( clicked() ),
139  this, SLOT ( load_distro() ) );
140  connect( pb_reset, SIGNAL( clicked() ),
141  this, SLOT ( resetAll() ) );
142  connect( pb_details, SIGNAL( clicked() ),
143  this, SLOT ( runDetails() ) );
144  connect( cb_sstart, SIGNAL( currentIndexChanged( int ) ),
145  this, SLOT ( changeSedcoeff( ) ) );
146  connect( cb_send, SIGNAL( currentIndexChanged( int ) ),
147  this, SLOT ( changeSedcoeff( ) ) );
148  connect( cb_lstart, SIGNAL( currentIndexChanged( int ) ),
149  this, SLOT ( changeLambda( ) ) );
150  connect( cb_lend, SIGNAL( currentIndexChanged( int ) ),
151  this, SLOT ( changeLambda( ) ) );
152  connect( ct_smooth, SIGNAL( valueChanged( double ) ),
153  this, SLOT ( changeSmooth() ) );
154  connect( cb_pltrec, SIGNAL( currentIndexChanged( int ) ),
155  this, SLOT ( changeRecord( ) ) );
156  connect( pb_prev, SIGNAL( clicked() ),
157  this, SLOT ( prevPlot() ) );
158  connect( pb_next, SIGNAL( clicked() ),
159  this, SLOT ( nextPlot() ) );
160  connect( pb_plot2d, SIGNAL( clicked() ),
161  this, SLOT ( changeRecord() ) );
162  connect( pb_movie2d, SIGNAL( clicked() ),
163  this, SLOT ( show_2d_movie() ) );
164  connect( pb_plot3d, SIGNAL( clicked() ),
165  this, SLOT ( plot_3d() ) );
166  connect( pb_svplot, SIGNAL( clicked() ),
167  this, SLOT ( save_plot() ) );
168  connect( pb_svmovie, SIGNAL( clicked() ),
169  this, SLOT ( save_movie() ) );
170  connect( pb_help, SIGNAL( clicked() ),
171  this, SLOT ( help() ) );
172  connect( pb_close, SIGNAL( clicked() ),
173  this, SLOT ( close() ) );
174 
175  // Do the left-side layout
176  int row = 0;
177  settings->addLayout( dkdb_cntrls, row++, 0, 1, 8 );
178  settings->addWidget( lb_run, row++, 0, 1, 8 );
179  settings->addWidget( pb_prefilt, row, 0, 1, 4 );
180  settings->addWidget( pb_loaddis, row++, 4, 1, 4 );
181  settings->addWidget( pb_reset, row, 0, 1, 4 );
182  settings->addWidget( pb_details, row++, 4, 1, 4 );
183  settings->addWidget( lb_prcntls, row++, 0, 1, 8 );
184  settings->addWidget( lb_sstart, row, 0, 1, 2 );
185  settings->addWidget( cb_sstart, row, 2, 1, 2 );
186  settings->addWidget( lb_send, row, 4, 1, 2 );
187  settings->addWidget( cb_send, row++, 6, 1, 2 );
188  settings->addWidget( lb_lstart, row, 0, 1, 2 );
189  settings->addWidget( cb_lstart, row, 2, 1, 2 );
190  settings->addWidget( lb_lend, row, 4, 1, 2 );
191  settings->addWidget( cb_lend, row++, 6, 1, 2 );
192  settings->addWidget( lb_smooth, row, 0, 1, 4 );
193  settings->addWidget( ct_smooth, row++, 4, 1, 2 );
194  settings->addWidget( lb_pltrec, row, 0, 1, 2 );
195  settings->addWidget( cb_pltrec, row, 2, 1, 2 );
196  settings->addWidget( pb_prev, row, 4, 1, 2 );
197  settings->addWidget( pb_next, row++, 6, 1, 2 );
198  settings->addWidget( lb_advplot, row++, 0, 1, 8 );
199  settings->addWidget( pb_plot2d, row, 0, 1, 4 );
200  settings->addWidget( pb_movie2d, row++, 4, 1, 4 );
201  settings->addWidget( pb_plot3d, row, 0, 1, 4 );
202  settings->addWidget( lb_delay, row, 4, 1, 2 );
203  settings->addWidget( ct_delay, row++, 6, 1, 2 );
204  settings->addWidget( pb_svplot, row, 0, 1, 4 );
205  settings->addWidget( pb_svmovie, row++, 4, 1, 4 );
206  settings->addWidget( lb_status, row++, 0, 1, 8 );
207  settings->addWidget( le_status, row++, 0, 1, 8 );
208  settings->addWidget( pb_help, row, 0, 1, 4 );
209  settings->addWidget( pb_close, row++, 4, 1, 4 );
210 
211  // Plot layout for the right side of window
212  QBoxLayout* plot = new US_Plot( data_plot,
213  tr( "S Record Spectrum Data"
214  "\nS (x 10^13) : 1.12" ),
215  tr( "Wavelength (nm)" ),
216  tr( "Concentration (OD)" ) );
217 
218  data_plot->setMinimumSize( 600, 400 );
219 
220  data_plot->enableAxis( QwtPlot::xBottom, true );
221  data_plot->enableAxis( QwtPlot::yLeft , true );
222 
223  data_plot->setAxisScale( QwtPlot::xBottom, 230, 450 );
224  data_plot->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
225 
226  picker = new US_PlotPicker( data_plot );
227  picker->setRubberBand ( QwtPicker::VLineRubberBand );
228  picker->setMousePattern ( QwtEventPattern::MouseSelect1,
229  Qt::LeftButton, Qt::ControlModifier );
230 
231  // Now let's assemble the page
232 
233  QVBoxLayout* left = new QVBoxLayout;
234  QVBoxLayout* right = new QVBoxLayout;
235  QHBoxLayout* main = new QHBoxLayout( this );
236 
237  left ->addLayout( settings );
238  right->addLayout( plot );
239 
240  main->setSpacing ( 2 );
241  main->setContentsMargins ( 2, 2, 2, 2 );
242  main->addLayout( left );
243  main->addLayout( right );
244  main->setStretch( 0, 2 );
245  main->setStretch( 1, 4 );
246 
247  reset();
248  adjustSize();
249 }
250 
251 // Completely reset GUI element states and all data
253 {
254  pb_prefilt->setEnabled( true );
255  pb_loaddis->setEnabled( true );
256  pb_details->setEnabled( false );
257  cb_sstart ->setEnabled( false );
258  cb_send ->setEnabled( false );
259  cb_lstart ->setEnabled( false );
260  cb_lend ->setEnabled( false );
261  ct_smooth ->setEnabled( false );
262  cb_pltrec ->setEnabled( false );
263  pb_prev ->setEnabled( false );
264  pb_next ->setEnabled( false );
265  pb_reset ->setEnabled( false );
266  pb_plot2d ->setEnabled( false );
267  pb_movie2d->setEnabled( false );
268  pb_plot3d ->setEnabled( false );
269  pb_svplot ->setEnabled( false );
270  pb_svmovie->setEnabled( false );
271 
272  // Clear any data structures
273  lambdas .clear();
274  sedcoes .clear();
275 
276  data_plot->detachItems();
277  picker ->disconnect();
278  data_plot->setAxisScale( QwtPlot::xBottom, 230, 450 );
279  data_plot->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
280  grid = us_grid( data_plot );
281  data_plot->replot();
282 
283  last_xmin = -1.0;
284  last_xmax = -1.0;
285  last_ymin = -1.0;
286  last_ymax = -1.0;
287 
288  le_status->setText( tr( "(no distributions loaded)" ) );
289 }
290 
291 // Slot to reset
293 {
294  if ( mdlxyz.count() > 0 )
295  {
296  int status = QMessageBox::information( this,
297  tr( "New Data Warning" ),
298  tr( "This will erase all data currently on the screen, and "
299  "reset the program to its starting condition. No hard-drive "
300  "data or database information will be affected. Proceed? " ),
301  tr( "&OK" ), tr( "&Cancel" ),
302  0, 0, 1 );
303  if ( status != 0 ) return;
304  }
305 
306  reset();
307 
308  runID = "";
309  data_plot->setTitle( tr( "S Record Spectrum Data"
310  "\nS (x 10^13) : 1.00" ) );
311 }
312 
313 
314 // Enable the common dialog controls based on the presence of data
316 {
317  if ( mdlxyz.count() == 0 )
318  { // If no data yet, just reset
319  reset();
320  return;
321  }
322 
323  // Enable and disable controls now
324  pb_prefilt->setEnabled( false );
325  pb_loaddis->setEnabled( false );
326  pb_reset ->setEnabled( true );
327  pb_details->setEnabled( true );
328  cb_sstart ->setEnabled( true );
329  cb_send ->setEnabled( true );
330  cb_lstart ->setEnabled( true );
331  cb_lend ->setEnabled( true );
332  ct_smooth ->setEnabled( true );
333  cb_pltrec ->setEnabled( true );
334  pb_prev ->setEnabled( true );
335  pb_next ->setEnabled( true );
336  pb_plot2d ->setEnabled( true );
337  pb_movie2d->setEnabled( true );
338  pb_plot3d ->setEnabled( true );
339  pb_svplot ->setEnabled( true );
340  pb_svmovie->setEnabled( true );
341 
342  nlambda = lambdas .count();
343  nsedcos = sedcoes .count();
344  ntpoint = nlambda * nsedcos;
345  QStringList slscos;
346  QStringList sllmbs;
347 
348  for ( int jj = 0; jj < nsedcos; jj++ )
349  slscos << QString::number( sedcoes[ jj ] );
350 
351  for ( int jj = 0; jj < nlambda; jj++ )
352  sllmbs << QString::number( lambdas[ jj ] );
353 
354  connect_ranges( false );
355  cb_sstart ->clear();
356  cb_send ->clear();
357  cb_lstart ->clear();
358  cb_lend ->clear();
359  cb_pltrec ->clear();
360 
361  cb_sstart ->addItems( slscos );
362  cb_send ->addItems( slscos );
363  cb_lstart ->addItems( sllmbs );
364  cb_lend ->addItems( sllmbs );
365  cb_pltrec ->addItems( slscos );
366 
367  cb_sstart ->setCurrentIndex( 0 );
368  cb_send ->setCurrentIndex( nsedcos - 1 );
369  cb_lstart ->setCurrentIndex( 0 );
370  cb_lend ->setCurrentIndex( nlambda - 1 );
371  connect_ranges( true );
372 
373  have_rngs = false;
374  compute_ranges( );
375 
376  // Force a plot initialize
377  cb_pltrec ->setCurrentIndex( nlambda / 2 );
378  qApp->processEvents();
379 }
380 
381 // Select raw/edit run(s) as model prefilter
383 {
384  pfilts.clear();
385 
386  US_SelectRuns srdiag( dkdb_cntrls->db(), pfilts );
387  srdiag.move( this->pos() + QPoint( 200, 200 ) );
388  connect( &srdiag, SIGNAL( dkdb_changed ( bool ) ),
389  this, SLOT ( update_disk_db( bool ) ) );
390 
391  if ( srdiag.exec() != QDialog::Accepted )
392  pfilts.clear();
393 }
394 
395 // Load model distribution(s)
397 {
398  // Get models and model descriptions
399  QList< US_Model > models;
400  bool loadDB = dkdb_cntrls->db();
401 
402  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
403  US_ModelLoader lddiag( loadDB, mfilter, models, mdescs, pfilts );
404  lddiag.move( this->pos() + QPoint( 200, 200 ) );
405 
406  connect( &lddiag, SIGNAL( changed ( bool ) ),
407  this, SLOT ( update_disk_db( bool ) ) );
408  QApplication::restoreOverrideCursor();
409 
410  if ( lddiag.exec() != QDialog::Accepted )
411  return; // No selection made
412 
413  // Load all models and build preliminary vectors
414 
415  mdlxyz .clear();
416  xyzdat .clear();
417  lambdas.clear();
418  sedcoes.clear();
419  wl_min = 1e+39;
420  wl_max = 1e-39;
421  se_min = 1e+39;
422  se_max = 1e-39;
423  co_min = 1e+39;
424  co_max = 1e-39;
425  nipoint = 0;
426  nnpoint = 0;
427  ntpoint = 0;
428 
429  resetAll();
430 
431  for ( int jj = 0; jj < models.count(); jj++ )
432  { // Load each selected distribution model
433  load_distro( models[ jj ], mdescs[ jj ] );
434  }
435 
436  // Sort points and build normalized concentrations
437 
438  qSort( sedcoes );
439  qSort( lambdas );
440  nsedcos = sedcoes.count();
441  nlambda = lambdas.count();
442  nipoint = mdlxyz .count();
443 DbgLv(1) << "LD: nlambda" << nlambda << "nsedcos" << nsedcos
444  << "nipoint" << nipoint;
445  nc_max = 0;
446  cn_max = 0.0;
447  double scalen = 1.0 / (double)models.count(); // Normalizing scale factor
448 
449  for ( int jj = 0; jj < nsedcos; jj++ )
450  {
451  double sedco = sedcoes[ jj ];
452 DbgLv(1) << "LD: jj" << jj << "sedco" << sedco;
453 
454  for ( int ii = 0; ii < nlambda; ii++ )
455  {
456  double waveln = (double)lambdas[ ii ];
457 DbgLv(1) << "LD: ii" << ii << "waveln" << waveln;
458  double conc = 0.0;
459  double csum = 0.0;
460  int nconcs = 0;
461 
462  for ( int kk = 0; kk < nipoint; kk++ )
463  {
464 if(kk<2||(kk+3)>nipoint)
465 DbgLv(1) << "LD: kk" << kk << "X,Y" << mdlxyz[kk].x() << mdlxyz[kk].y();
466  if ( dvirt_equal( mdlxyz[ kk ].y(), sedco ) &&
467  dvirt_equal( mdlxyz[ kk ].x(), waveln ) )
468  {
469  nconcs++;
470  csum += mdlxyz[ kk ].z();
471  }
472  }
473 
474  if ( nconcs > 0 )
475  { // Normalize concentration by dividing sum by number of models
476  conc = csum * scalen;
477  nc_max = qMax( nc_max, nconcs );
478  cn_max = qMax( cn_max, conc );
479  nnpoint++;
480 if(nconcs>5||conc>1000.0)
481 DbgLv(1) << "LD: **nc_max cn_max" << nc_max << cn_max << "nconcs conc"
482  << nconcs << conc << "jj,ii" << jj << ii << "s wl" << sedco << waveln;
483  }
484 
485  else
486  {
487  conc = 0.0;
488  }
489 
490  xyzdat << QVector3D( waveln, sedco, conc );
491 DbgLv(1) << "LD: nconcs" << nconcs;
492  }
493  }
494 
495  ntpoint = xyzdat .count();
496 DbgLv(1) << "LD: nipoint" << nipoint << "nnpoint" << nnpoint << "ntpoint"
497  << ntpoint << "nc_max" << nc_max << "cn_max" << cn_max;
498  int kdx = 0;
499 
500  // Create the 2-D concentration vectors for each sed.coeff.
501  for ( int jj = 0; jj < nsedcos; jj++ )
502  {
503  QVector< double > cvect;
504 
505  for ( int ii = 0; ii < nlambda; ii++ )
506  {
507  cvect << xyzdat[ kdx++ ].z();
508  }
509 
510  // Save the concentration vector for lambdas of this sedcoeff
511  concdat << cvect;
512  }
513 DbgLv(1) << "LD: concdat size" << concdat.size() << nsedcos;
514 
515  // Ok to enable some buttons now
516  enableControls();
517 }
518 
519 // Load distributions from a single model
520 void US_MwlSpectra::load_distro( const US_Model model, const QString mdescr )
521 {
522  QString mdesc = mdescr.section( mdescr.left( 1 ), 1, 1 );
523  int lambda = qRound( model.wavelength );
524 
525  if ( lambda < 1 )
526  { // If model has no wavelength, get it from the description
527  mdesc = mdesc.endsWith( "model" ) ? mdesc : model.description;
528  lambda = mdesc.section( ".", -3, -3 ).mid( 2 ).toInt();
529  }
530 
531  if ( runID.isEmpty() )
532  {
533  runID = mdesc.section( ".", -4, -4 );
534  }
535 
536  double waveln = (double)lambda;
537  wl_min = qMin( wl_min, waveln );
538  wl_max = qMax( wl_max, waveln );
539  if ( ! lambdas.contains( lambda ) )
540  lambdas << lambda;
541 
542  for ( int jj = 0; jj < model.components.size(); jj++ )
543  {
544  double sedc = model.components[ jj ].s * 1e+13;
545  double conc = model.components[ jj ].signal_concentration;
546  se_min = qMin( se_min, sedc );
547  se_max = qMax( se_max, sedc );
548  co_min = qMin( co_min, conc );
549  co_max = qMax( co_max, conc );
550 
551  mdlxyz << QVector3D( waveln, sedc, conc );
552 if(conc>1000.0)
553 DbgLv(1) << "LD: **co_max" << co_max << "conc" << conc << "jj" << jj
554  << "lambda sedc" << lambda << sedc << "mdesc" << mdesc;
555 
556  if ( ! sedcoes.contains( sedc ) )
557  sedcoes << sedc;
558  }
559 }
560 
561 // Display detailed information about the data
563 {
564  // Set base values
565  int nmodels = mdescs.count();
566  int lmx = nmodels - 1;
567  QString fmd = mdescs[ 0 ].section( mdescs[ 0 ].left( 1 ), 1, 1 );
568  QString lmd = mdescs[ lmx ].section( mdescs[ lmx ].left( 1 ), 1, 1 );
569 
570  // Accumulate statistics for whole, selected sedcoeffs, selected lambdas
571  double wln1 = (double)lambdas[ 0 ];
572  double wln2 = (double)lambdas[ nlambda / 4 ];
573  double wln3 = (double)lambdas[ nlambda / 2 ];
574  double wln4 = (double)lambdas[ ( nlambda * 3 ) / 4 ];
575  double wln5 = (double)lambdas[ nlambda - 1 ];
576  double sed1 = sedcoes[ 0 ];
577  double sed2 = sedcoes[ nsedcos / 4 ];
578  double sed3 = sedcoes[ nsedcos / 2 ];
579  double sed4 = sedcoes[ ( nsedcos * 3 ) / 4 ];
580  double sed5 = sedcoes[ nsedcos - 1 ];
581  QVector< int > istaa;
582  QVector< double > dstaa;
583  QVector< double > lmbsa;
584  QVector< double > sedsa;
585  QVector< double > consa;
586  QVector< int > istaw1;
587  QVector< double > dstaw1;
588  QVector< double > lmbsw1;
589  QVector< double > sedsw1;
590  QVector< double > consw1;
591  QVector< int > istaw2;
592  QVector< double > dstaw2;
593  QVector< double > lmbsw2;
594  QVector< double > sedsw2;
595  QVector< double > consw2;
596  QVector< int > istaw3;
597  QVector< double > dstaw3;
598  QVector< double > lmbsw3;
599  QVector< double > sedsw3;
600  QVector< double > consw3;
601  QVector< int > istaw4;
602  QVector< double > dstaw4;
603  QVector< double > lmbsw4;
604  QVector< double > sedsw4;
605  QVector< double > consw4;
606  QVector< int > istaw5;
607  QVector< double > dstaw5;
608  QVector< double > lmbsw5;
609  QVector< double > sedsw5;
610  QVector< double > consw5;
611  QVector< int > istas1;
612  QVector< double > dstas1;
613  QVector< double > lmbss1;
614  QVector< double > sedss1;
615  QVector< double > conss1;
616  QVector< int > istas2;
617  QVector< double > dstas2;
618  QVector< double > lmbss2;
619  QVector< double > sedss2;
620  QVector< double > conss2;
621  QVector< int > istas3;
622  QVector< double > dstas3;
623  QVector< double > lmbss3;
624  QVector< double > sedss3;
625  QVector< double > conss3;
626  QVector< int > istas4;
627  QVector< double > dstas4;
628  QVector< double > lmbss4;
629  QVector< double > sedss4;
630  QVector< double > conss4;
631  QVector< int > istas5;
632  QVector< double > dstas5;
633  QVector< double > lmbss5;
634  QVector< double > sedss5;
635  QVector< double > conss5;
636 
637  istaa .fill( 0, 3 );
638  dstaa .fill( 0.0, 10 );
639  istaw1.fill( 0, 3 );
640  dstaw1.fill( 0.0, 10 );
641  istaw2.fill( 0, 3 );
642  dstaw2.fill( 0.0, 10 );
643  istaw3.fill( 0, 3 );
644  dstaw3.fill( 0.0, 10 );
645  istaw4.fill( 0, 3 );
646  dstaw4.fill( 0.0, 10 );
647  istaw5.fill( 0, 3 );
648  dstaw5.fill( 0.0, 10 );
649  istas1.fill( 0, 3 );
650  dstas1.fill( 0.0, 10 );
651  istas2.fill( 0, 3 );
652  dstas2.fill( 0.0, 10 );
653  istas3.fill( 0, 3 );
654  dstas3.fill( 0.0, 10 );
655  istas4.fill( 0, 3 );
656  dstas4.fill( 0.0, 10 );
657  istas5.fill( 0, 3 );
658  dstas5.fill( 0.0, 10 );
659 
660  for ( int ii = 0; ii < mdlxyz.count(); ii++ )
661  {
662  double wlnv = mdlxyz[ ii ].x();
663  double sedv = mdlxyz[ ii ].y();
664  double conv = mdlxyz[ ii ].z();
665 
666  if ( conv == 0.0 ) continue;
667 
668  bld_stats( wlnv, sedv, conv, istaa, dstaa, lmbsa, sedsa, consa );
669 
670  if ( dvirt_equal( wlnv, wln1 ) )
671  {
672  bld_stats( wlnv, sedv, conv, istaw1, dstaw1, lmbsw1, sedsw1, consw1 );
673  }
674 
675  else if ( dvirt_equal( wlnv, wln2 ) )
676  {
677  bld_stats( wlnv, sedv, conv, istaw2, dstaw2, lmbsw2, sedsw2, consw2 );
678  }
679 
680  else if ( dvirt_equal( wlnv, wln3 ) )
681  {
682  bld_stats( wlnv, sedv, conv, istaw3, dstaw3, lmbsw3, sedsw3, consw3 );
683  }
684 
685  else if ( dvirt_equal( wlnv, wln4 ) )
686  {
687  bld_stats( wlnv, sedv, conv, istaw4, dstaw4, lmbsw4, sedsw4, consw4 );
688  }
689 
690  else if ( dvirt_equal( wlnv, wln5 ) )
691  {
692  bld_stats( wlnv, sedv, conv, istaw5, dstaw5, lmbsw5, sedsw5, consw5 );
693  }
694 
695  if ( dvirt_equal( sedv, sed1 ) )
696  {
697  bld_stats( wlnv, sedv, conv, istas1, dstas1, lmbss1, sedss1, conss1 );
698  }
699 
700  else if ( dvirt_equal( sedv, sed2 ) )
701  {
702  bld_stats( wlnv, sedv, conv, istas2, dstas2, lmbss2, sedss2, conss2 );
703  }
704 
705  else if ( dvirt_equal( sedv, sed3 ) )
706  {
707  bld_stats( wlnv, sedv, conv, istas3, dstas3, lmbss3, sedss3, conss3 );
708  }
709 
710  else if ( dvirt_equal( sedv, sed4 ) )
711  {
712  bld_stats( wlnv, sedv, conv, istas4, dstas4, lmbss4, sedss4, conss4 );
713  }
714 
715  else if ( dvirt_equal( sedv, sed5 ) )
716  {
717  bld_stats( wlnv, sedv, conv, istas5, dstas5, lmbss5, sedss5, conss5 );
718  }
719  }
720 
721  // Complete statistical values
722  final_stats( istaa, dstaa, lmbsa, sedsa, consa );
723  final_stats( istaw1, dstaw1, lmbsw1, sedsw1, consw1 );
724  final_stats( istaw2, dstaw2, lmbsw2, sedsw2, consw2 );
725  final_stats( istaw3, dstaw3, lmbsw3, sedsw3, consw3 );
726  final_stats( istaw4, dstaw4, lmbsw4, sedsw4, consw4 );
727  final_stats( istaw5, dstaw5, lmbsw5, sedsw5, consw5 );
728  final_stats( istas1, dstas1, lmbss1, sedss1, conss1 );
729  final_stats( istas2, dstas2, lmbss2, sedss2, conss2 );
730  final_stats( istas3, dstas3, lmbss3, sedss3, conss3 );
731  final_stats( istas4, dstas4, lmbss4, sedss4, conss4 );
732  final_stats( istas5, dstas5, lmbss5, sedss5, conss5 );
733 
734  // Construct the report text
735  QString msg = tr( "Multi-Wavelength Statistics for RunID %1 --\n\n" )
736  .arg( runID );
737  msg += tr( "General Models Values and Counts.\n" );
738  msg += tr( " First Model Description: %1\n" ).arg( fmd );
739  msg += tr( " Last Model Description: %1\n" ).arg( lmd );
740  msg += tr( " Models Loaded: %1\n" ).arg( nmodels );
741  msg += tr( " Sedimentation Coefficients: %1\n" ).arg( nsedcos );
742  msg += tr( " Wavelengths: %1\n" ).arg( nlambda );
743  msg += tr( " Total Loaded Points: %1\n" ).arg( nipoint );
744  msg += tr( "\nNormalized Composite Input Grid.\n" );
745  msg += tr( " Points after Normalizing: %1\n" ).arg( nnpoint );
746  msg += tr( " Maximum Single-Bin Points: %1\n" ).arg( nc_max );
747  msg += tr( " Maximum Concentration (OD): %1\n" ).arg( cn_max );
748  msg += tr( "Padded Full S x Lambda Grid.\n" );
749  msg += tr( " Grid Points: %1\n" ).arg( ntpoint );
750  msg += tr( " Minimum Sedimentation Coeff.: %1\n" ).arg( se_min );
751  msg += tr( " Maximum Sedimentation Coeff.: %1\n" ).arg( se_max );
752  msg += tr( " Minimum Wavelength (nm): %1\n" ).arg( wl_min );
753  msg += tr( " Maximum Wavelength (nm): %1\n" ).arg( wl_max );
754  msg += tr( " Minimum Concentration (OD): %1\n" ).arg( co_min );
755  msg += tr( " Maximum Concentration (OD): %1\n" ).arg( co_max );
756  msg += tr( "Current Plotting Controls.\n" );
757  msg += tr( " Start Sedimentation Coeff.: %1\n" ).arg( sed_start );
758  msg += tr( " End Sedimentation Coeff.: %1\n" ).arg( sed_end );
759  msg += tr( " Start Wavelength: %1\n" ).arg( lmb_start );
760  msg += tr( " End Wavelength: %1\n" ).arg( lmb_end );
761 
762  msg += tr( "\nStatistical Details for the Full Model set.\n" );
763  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaa[ 0 ] );
764  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaa[ 1 ] );
765  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaa[ 2 ] );
766  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaa[ 0 ] );
767  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaa[ 1 ] );
768  msg += tr( " Mean Concentration: %1\n" ).arg( dstaa[ 4 ] );
769  msg += tr( " Median Concentration: %1\n" ).arg( dstaa[ 9 ] );
770  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaa[ 2 ] );
771  msg += tr( " Median Wavelength: %1\n" ).arg( dstaa[ 7 ] );
772  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaa[ 5 ] );
773  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaa[ 3 ] );
774  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaa[ 8 ] );
775  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaa[ 6 ] );
776  msg += tr( "\nStatistical Details for Wavelength %1 .\n" ).arg( wln1 );
777  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaw1[ 0 ] );
778  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaw1[ 1 ] );
779  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaw1[ 2 ] );
780  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaw1[ 0 ] );
781  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaw1[ 1 ] );
782  msg += tr( " Mean Concentration: %1\n" ).arg( dstaw1[ 4 ] );
783  msg += tr( " Median Concentration: %1\n" ).arg( dstaw1[ 9 ] );
784  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaw1[ 2 ] );
785  msg += tr( " Median Wavelength: %1\n" ).arg( dstaw1[ 7 ] );
786  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaw1[ 5 ] );
787  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaw1[ 3 ] );
788  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaw1[ 8 ] );
789  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaw1[ 6 ] );
790  msg += tr( "Statistical Details for Wavelength %1 .\n" ).arg( wln2 );
791  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaw2[ 0 ] );
792  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaw2[ 1 ] );
793  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaw2[ 2 ] );
794  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaw2[ 0 ] );
795  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaw2[ 1 ] );
796  msg += tr( " Mean Concentration: %1\n" ).arg( dstaw2[ 4 ] );
797  msg += tr( " Median Concentration: %1\n" ).arg( dstaw2[ 9 ] );
798  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaw2[ 2 ] );
799  msg += tr( " Median Wavelength: %1\n" ).arg( dstaw2[ 7 ] );
800  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaw2[ 5 ] );
801  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaw2[ 3 ] );
802  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaw2[ 8 ] );
803  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaw2[ 6 ] );
804  msg += tr( "Statistical Details for Wavelength %1 .\n" ).arg( wln3 );
805  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaw3[ 0 ] );
806  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaw3[ 1 ] );
807  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaw3[ 2 ] );
808  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaw3[ 0 ] );
809  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaw3[ 1 ] );
810  msg += tr( " Mean Concentration: %1\n" ).arg( dstaw3[ 4 ] );
811  msg += tr( " Median Concentration: %1\n" ).arg( dstaw3[ 9 ] );
812  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaw3[ 2 ] );
813  msg += tr( " Median Wavelength: %1\n" ).arg( dstaw3[ 7 ] );
814  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaw3[ 5 ] );
815  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaw3[ 3 ] );
816  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaw3[ 8 ] );
817  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaw3[ 6 ] );
818  msg += tr( "Statistical Details for Wavelength %1 .\n" ).arg( wln4 );
819  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaw4[ 0 ] );
820  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaw4[ 1 ] );
821  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaw4[ 2 ] );
822  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaw4[ 0 ] );
823  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaw4[ 1 ] );
824  msg += tr( " Mean Concentration: %1\n" ).arg( dstaw4[ 4 ] );
825  msg += tr( " Median Concentration: %1\n" ).arg( dstaw4[ 9 ] );
826  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaw4[ 2 ] );
827  msg += tr( " Median Wavelength: %1\n" ).arg( dstaw4[ 7 ] );
828  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaw4[ 5 ] );
829  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaw4[ 3 ] );
830  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaw4[ 8 ] );
831  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaw4[ 6 ] );
832  msg += tr( "Statistical Details for Wavelength %1 .\n" ).arg( wln5 );
833  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istaw5[ 0 ] );
834  msg += tr( " Count of Wavelengths: %1\n" ).arg( istaw5[ 1 ] );
835  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istaw5[ 2 ] );
836  msg += tr( " Minimum Concentration: %1\n" ).arg( dstaw5[ 0 ] );
837  msg += tr( " Maximum Concentration: %1\n" ).arg( dstaw5[ 1 ] );
838  msg += tr( " Mean Concentration: %1\n" ).arg( dstaw5[ 4 ] );
839  msg += tr( " Median Concentration: %1\n" ).arg( dstaw5[ 9 ] );
840  msg += tr( " Mean Wavelength: %1\n" ).arg( dstaw5[ 2 ] );
841  msg += tr( " Median Wavelength: %1\n" ).arg( dstaw5[ 7 ] );
842  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstaw5[ 5 ] );
843  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstaw5[ 3 ] );
844  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstaw5[ 8 ] );
845  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstaw5[ 6 ] );
846  msg += tr( "\nStatistical Details for Sed.Coeff. %1 .\n" ).arg( sed1 );
847  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istas1[ 0 ] );
848  msg += tr( " Count of Wavelengths: %1\n" ).arg( istas1[ 1 ] );
849  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istas1[ 2 ] );
850  msg += tr( " Minimum Concentration: %1\n" ).arg( dstas1[ 0 ] );
851  msg += tr( " Maximum Concentration: %1\n" ).arg( dstas1[ 1 ] );
852  msg += tr( " Mean Concentration: %1\n" ).arg( dstas1[ 4 ] );
853  msg += tr( " Median Concentration: %1\n" ).arg( dstas1[ 9 ] );
854  msg += tr( " Mean Wavelength: %1\n" ).arg( dstas1[ 2 ] );
855  msg += tr( " Median Wavelength: %1\n" ).arg( dstas1[ 7 ] );
856  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstas1[ 5 ] );
857  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstas1[ 3 ] );
858  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstas1[ 8 ] );
859  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstas1[ 6 ] );
860  msg += tr( "Statistical Details for Sed.Coeff. %1 .\n" ).arg( sed2 );
861  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istas2[ 0 ] );
862  msg += tr( " Count of Wavelengths: %1\n" ).arg( istas2[ 1 ] );
863  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istas2[ 2 ] );
864  msg += tr( " Minimum Concentration: %1\n" ).arg( dstas2[ 0 ] );
865  msg += tr( " Maximum Concentration: %1\n" ).arg( dstas2[ 1 ] );
866  msg += tr( " Mean Concentration: %1\n" ).arg( dstas2[ 4 ] );
867  msg += tr( " Median Concentration: %1\n" ).arg( dstas2[ 9 ] );
868  msg += tr( " Mean Wavelength: %1\n" ).arg( dstas2[ 2 ] );
869  msg += tr( " Median Wavelength: %1\n" ).arg( dstas2[ 7 ] );
870  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstas2[ 5 ] );
871  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstas2[ 3 ] );
872  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstas2[ 8 ] );
873  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstas2[ 6 ] );
874  msg += tr( "Statistical Details for Sed.Coeff. %1 .\n" ).arg( sed3 );
875  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istas3[ 0 ] );
876  msg += tr( " Count of Wavelengths: %1\n" ).arg( istas3[ 1 ] );
877  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istas3[ 2 ] );
878  msg += tr( " Minimum Concentration: %1\n" ).arg( dstas3[ 0 ] );
879  msg += tr( " Maximum Concentration: %1\n" ).arg( dstas3[ 1 ] );
880  msg += tr( " Mean Concentration: %1\n" ).arg( dstas3[ 4 ] );
881  msg += tr( " Median Concentration: %1\n" ).arg( dstas3[ 9 ] );
882  msg += tr( " Mean Wavelength: %1\n" ).arg( dstas3[ 2 ] );
883  msg += tr( " Median Wavelength: %1\n" ).arg( dstas3[ 7 ] );
884  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstas3[ 5 ] );
885  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstas3[ 3 ] );
886  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstas3[ 8 ] );
887  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstas3[ 6 ] );
888  msg += tr( "Statistical Details for Sed.Coeff. %1 .\n" ).arg( sed4 );
889  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istas4[ 0 ] );
890  msg += tr( " Count of Wavelengths: %1\n" ).arg( istas4[ 1 ] );
891  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istas4[ 2 ] );
892  msg += tr( " Minimum Concentration: %1\n" ).arg( dstas4[ 0 ] );
893  msg += tr( " Maximum Concentration: %1\n" ).arg( dstas4[ 1 ] );
894  msg += tr( " Mean Concentration: %1\n" ).arg( dstas4[ 4 ] );
895  msg += tr( " Median Concentration: %1\n" ).arg( dstas4[ 9 ] );
896  msg += tr( " Mean Wavelength: %1\n" ).arg( dstas4[ 2 ] );
897  msg += tr( " Median Wavelength: %1\n" ).arg( dstas4[ 7 ] );
898  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstas4[ 5 ] );
899  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstas4[ 3 ] );
900  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstas4[ 8 ] );
901  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstas4[ 6 ] );
902  msg += tr( "Statistical Details for Sed.Coeff. %1 .\n" ).arg( sed5 );
903  msg += tr( " Total Non-Zero Count: %1\n" ).arg( istas5[ 0 ] );
904  msg += tr( " Count of Wavelengths: %1\n" ).arg( istas5[ 1 ] );
905  msg += tr( " Count of Sed. Coeffs.: %1\n" ).arg( istas5[ 2 ] );
906  msg += tr( " Minimum Concentration: %1\n" ).arg( dstas5[ 0 ] );
907  msg += tr( " Maximum Concentration: %1\n" ).arg( dstas5[ 1 ] );
908  msg += tr( " Mean Concentration: %1\n" ).arg( dstas5[ 4 ] );
909  msg += tr( " Median Concentration: %1\n" ).arg( dstas5[ 9 ] );
910  msg += tr( " Mean Wavelength: %1\n" ).arg( dstas5[ 2 ] );
911  msg += tr( " Median Wavelength: %1\n" ).arg( dstas5[ 7 ] );
912  msg += tr( " Weighted Avg. Wavelength: %1\n" ).arg( dstas5[ 5 ] );
913  msg += tr( " Mean Sed. Coeff.: %1\n" ).arg( dstas5[ 3 ] );
914  msg += tr( " Median Sed. Coeff.: %1\n" ).arg( dstas5[ 8 ] );
915  msg += tr( " Weighted Avg. Sed. Coeff.: %1\n" ).arg( dstas5[ 6 ] );
916 
917  // Open the dialog and display the report text
918  US_Editor* editd = new US_Editor( US_Editor::DEFAULT, true );
919  editd->setWindowTitle( tr( "Multi-Wavelength Spectra Statistics" ) );
920  editd->move( pos() + QPoint( 200, 200 ) );
921  editd->resize( 600, 500 );
922  editd->e->setFont( QFont( US_Widgets::fixedFont().family(),
924  editd->e->setText( msg );
925  editd->show();
926 }
927 
928 // Plot the current data record
930 {
931  if ( mdlxyz.count() == 0 )
932  return;
933 
934  plot_titles(); // Set the titles
935 
936  plot_all(); // Plot the data
937 }
938 
939 // Compose plot titles for the current record
941 {
942  QString prec = cb_pltrec->currentText();
943 
944  // Plot Title
945  QString title = tr( "Sedimentation Coefficient Spectrum\n"
946  "Run ID : " ) + runID + "\ns (x 10^13) : " + prec;
947 
948  data_plot->setTitle( title );
949 }
950 
951 // Draw wavelength,concentration curves for the current sedcoeff plot record
953 {
954  data_plot->detachItems();
955  grid = us_grid( data_plot );
956 
957  // Make sure ranges are set up, then build a smoothed data vector
958  have_rngs = false;
959  compute_ranges();
960 
962 
963 int knz=0;
964 double cmx=0.0;
965 for(int ii=0;ii<kpoint;ii++)
966 { double cvl=pltyvals[ii];if(cvl!=0.0) knz++; cmx=qMax(cmx,cvl); }
967 DbgLv(1) << "PltA: kpoint" << kpoint << "knz" << knz << "cmx" << cmx;
968  // Point to the X,Y vectors
969  double* rr = pltxvals.data();
970  double* vv = pltyvals.data();
971 
972  QPen pen_plot( US_GuiSettings::plotCurve() );
973  QString title = tr( "s=%1 sindex=%2" ).arg( sed_plot ).arg( sedxp );
974  QwtPlotCurve* curv = us_curve( data_plot, title );
975 
976  curv->setPen( pen_plot ); // Normal pen
977 
978  curv->setData( rr, vv, kpoint ); // Build a sed.coeff. curve
979 //DbgLv(1) << "PltA: scx" << scx << "rr0 vv0 rrn vvn"
980 // << rr[0] << rr[kpoint-1] << vv[0] << vv[kpoint-1];
981 
982 DbgLv(1) << "PltA: last_xmin" << last_xmin;
983  if ( last_xmin < 0.0 )
984  { // If first time, set scales based on actual values present
985  last_xmin = lmb_start; // Set X limits
986  last_xmax = lmb_end;
987  last_ymin = 0.0; // Set Y limits
988  last_ymax = cn_max;
989  data_plot->setAxisScale( QwtPlot::xBottom, last_xmin, last_xmax );
990  data_plot->setAxisScale( QwtPlot::yLeft , last_ymin, last_ymax );
991  }
992 
993  else
994  { // After first time, use the same plot ranges as set before
995  data_plot->setAxisScale( QwtPlot::xBottom, last_xmin, last_xmax );
996  data_plot->setAxisScale( QwtPlot::yLeft , last_ymin, last_ymax );
997  }
998 
999  // Draw the plot
1000  data_plot->replot();
1001 
1002  // Pick up the actual bounds plotted (including any Config changes)
1003  QwtScaleDiv* sdx = data_plot->axisScaleDiv( QwtPlot::xBottom );
1004  QwtScaleDiv* sdy = data_plot->axisScaleDiv( QwtPlot::yLeft );
1005  last_xmin = sdx->lowerBound();
1006  last_xmax = sdx->upperBound();
1007  last_ymin = sdy->lowerBound();
1008  last_ymax = sdy->upperBound();
1009 DbgLv(1) << "PltA: xlo xhi" << last_xmin << last_xmax
1010  << "ylo yhi" << last_ymin << last_ymax;
1011 }
1012 
1013 // Slot to handle a change in start or end sedimentation coefficient
1015 {
1016 DbgLv(1) << "chgSedcoeff";
1017  // Recompute ranges
1018  have_rngs = false;
1019  compute_ranges();
1020 
1021  // Re-do the list of plot records
1022  connect_ranges( false );
1023  cb_pltrec->clear();
1024 
1025  for ( int jj = sedxs; jj < sedxe; jj++ )
1026  cb_pltrec->addItem( QString::number( sedcoes[ jj ] ) );
1027 
1028  // Recompute ranges
1029  have_rngs = false;
1030  compute_ranges();
1031 
1032  // Reset the current plot record
1034  sedxp = qMax( sedxs, qMin( sedxe, sedxp ) );
1035  connect_ranges( true );
1036  cb_pltrec->setCurrentIndex( sedxp );
1037 
1038 }
1039 
1040 // Slot to handle a change in start or end lambda
1042 {
1043 DbgLv(1) << "chgLambda";
1044  // Recompute ranges
1045  have_rngs = false;
1046  compute_ranges();
1047 
1048  // Reset plot X limits
1049  last_xmin = lmb_start;
1050  last_xmax = lmb_end;
1051 }
1052 
1053 // Slot to handle a change in the plot record
1055 {
1056  recx = cb_pltrec->currentIndex();
1057 DbgLv(1) << "chgRec: recx" << recx;
1058  bool plt_one = ! le_status->text().contains( tr( "saving" ) );
1059 
1060  // Plot what we have
1061  plot_current();
1062 
1063  // Update status text (if not part of movie save) and set prev/next arrows
1064  if ( plt_one )
1065  le_status->setText( lb_pltrec->text() + " " + cb_pltrec->currentText() );
1066  pb_prev ->setEnabled( ( recx > 0 ) );
1067  pb_next ->setEnabled( ( recx < ( cb_pltrec->count() - 1 ) ) );
1068 }
1069 
1070 // Slot to handle a click to go to the previous record
1072 {
1073  int pltrx = cb_pltrec->currentIndex() - 1;
1074 
1075  if ( pltrx < 1 )
1076  {
1077  pltrx = 0;
1078  pb_prev->setEnabled( false );
1079  }
1080 
1081  QwtScaleDiv* sdx = data_plot->axisScaleDiv( QwtPlot::xBottom );
1082  QwtScaleDiv* sdy = data_plot->axisScaleDiv( QwtPlot::yLeft );
1083  last_xmin = sdx->lowerBound();
1084  last_xmax = sdx->upperBound();
1085  last_ymin = sdy->lowerBound();
1086  last_ymax = sdy->upperBound();
1087 
1088  cb_pltrec->setCurrentIndex( pltrx );
1089 }
1090 
1091 // Slot to handle a click to go to the next record
1093 {
1094  int pltrx = cb_pltrec->currentIndex() + 1;
1095  int nitems = cb_pltrec->count();
1096 
1097  if ( ( pltrx + 2 ) > nitems )
1098  {
1099  pltrx = nitems - 1;
1100  pb_next->setEnabled( false );
1101  }
1102 
1103  QwtScaleDiv* sdx = data_plot->axisScaleDiv( QwtPlot::xBottom );
1104  QwtScaleDiv* sdy = data_plot->axisScaleDiv( QwtPlot::yLeft );
1105  last_xmin = sdx->lowerBound();
1106  last_xmax = sdx->upperBound();
1107  last_ymin = sdy->lowerBound();
1108  last_ymax = sdy->upperBound();
1109 
1110  cb_pltrec->setCurrentIndex( pltrx );
1111 }
1112 
1113 // Slot to handle a change in the number of smoothing points
1115 {
1116 DbgLv(1) << "chgSmooth:";
1117  nsmooth = ct_smooth->value();
1118 
1119  plot_all();
1120 }
1121 
1122 // Compute the plot range indexes implied by current settings
1124 {
1125  if ( have_rngs ) // If we just did this computation, return now
1126  return;
1127 
1128  sed_start = cb_sstart ->currentText().toDouble(); // Sedcoeff start
1129  sed_end = cb_send ->currentText().toDouble(); // Sedcoeff end
1130  lmb_start = cb_lstart ->currentText().toInt(); // Lambda start
1131  lmb_end = cb_lend ->currentText().toInt(); // Lambda end
1132  sed_plot = cb_pltrec ->currentText().toDouble(); // Sedcoeff plot record
1133  lmbxs = lambdas.indexOf( lmb_start ); // Lambda start index
1134  lmbxe = lambdas.indexOf( lmb_end ) + 1; // Lambda end index
1135  sedxs = dvec_index( sedcoes, sed_start ); // SedCoef start index
1136  sedxe = dvec_index( sedcoes, sed_end ) + 1; // SedCoef end index
1137  sedxp = dvec_index( sedcoes, sed_plot ); // SedCoef plot rec index
1138  recx = cb_pltrec->currentIndex(); // Index in plot sedcos
1139  klambda = lmbxe - lmbxs; // Count of plot lambdas
1140  ksedcos = sedxe - sedxs; // Count of plot sedcos
1141  kpoint = klambda; // Plot x,y points
1142  pltxvals.clear();
1143  pltyvals.clear();
1144 
1145  if ( sedxp < 0 || recx < 0 )
1146  {
1147 DbgLv(1) << "cmpR: (1)sS sE sxS sxE" << sed_start << sed_end << sedxs << sedxe
1148  << "sxP rx sP" << sedxp << recx << sed_plot;
1149  sed_plot = qMax( sed_start, qMin( sed_end, sed_plot ) );
1150  sedxp = dvec_index( sedcoes, sed_plot );
1151  recx = sedxp - sedxs;
1152  }
1153 DbgLv(1) << "cmpR: sS sE sxS sxE" << sed_start << sed_end << sedxs << sedxe
1154  << "sxP rx sP" << sedxp << recx << sed_plot;
1155 
1156  // Get lambda values in current plot range
1157  for ( int ii = lmbxs; ii < lmbxe; ii++ )
1158  pltxvals << (double)lambdas[ ii ];
1159 
1160  // Get concentrations from current sedcoeff record, in current lambda range
1161  for ( int ii = lmbxs; ii < lmbxe; ii++ )
1162  pltyvals << concdat[ sedxp ][ ii ];
1163 
1164  have_rngs = true; // Mark ranges computed
1165 }
1166 
1167 // Connect or Disconnect plot-range related controls
1169 {
1170  if ( conn )
1171  { // Connect the range-related controls
1172  connect( cb_sstart, SIGNAL( currentIndexChanged( int ) ),
1173  this, SLOT ( changeSedcoeff( ) ) );
1174  connect( cb_send, SIGNAL( currentIndexChanged( int ) ),
1175  this, SLOT ( changeSedcoeff( ) ) );
1176  connect( cb_lstart, SIGNAL( currentIndexChanged( int ) ),
1177  this, SLOT ( changeLambda( ) ) );
1178  connect( cb_lend, SIGNAL( currentIndexChanged( int ) ),
1179  this, SLOT ( changeLambda( ) ) );
1180  connect( cb_pltrec, SIGNAL( currentIndexChanged( int ) ),
1181  this, SLOT ( changeRecord( ) ) );
1182  }
1183 
1184  else
1185  { // Disconnect the range-related controls
1186  cb_sstart ->disconnect();
1187  cb_send ->disconnect();
1188  cb_lstart ->disconnect();
1189  cb_lend ->disconnect();
1190  cb_pltrec ->disconnect();
1191  }
1192 }
1193 
1194 // Slot to show a 2-D movie
1196 {
1197 DbgLv(1) << "Show 2D Movie";
1198  // Loop to plot each record in the current cell
1199  int krecs = cb_pltrec->count();
1200  int svrec = recx; // Save currently plotted record
1201  int mdelay = (int)qRound( ct_delay->value() * 1000.0 );
1202 
1203  for ( int prx = 0; prx < krecs; prx++ )
1204  {
1205  cb_pltrec->setCurrentIndex( prx ); // Plot each record in the range
1206  qApp->processEvents();
1207  US_Sleep::msleep( mdelay ); // Delay between frames
1208  }
1209 
1210  cb_pltrec->setCurrentIndex( svrec ); // Restore previous plot record
1211  qApp->processEvents();
1212 }
1213 
1214 // Slot to open a dialog for 3-D plotting
1216 {
1217 DbgLv(1) << "Plt3D";
1218  // Create a 3D plot version of the data with ranges and smoothing
1219 
1220  compute_ranges();
1221 
1222  p3dxyz.clear();
1223 
1224  // Create the 2-D concentration vectors for each sed.coeff.
1225  for ( int jj = sedxs; jj < sedxe; jj++ )
1226  {
1227  QVector< double > cvect;
1228  int jd = jj * nlambda;
1229  double sedv = xyzdat[ jd ].y();
1230 
1231  for ( int ii = lmbxs; ii < lmbxe; ii++ )
1232  { // Create the concentration vector for this sed.coeff.
1233  cvect << xyzdat[ jd + ii ].z();
1234  }
1235 
1236  // Smooth the vector
1238  jd += lmbxs;
1239 
1240  // Output the XYZ points with smoothed concentrations
1241  for ( int ii = 0; ii < cvect.count(); ii++, jd++ )
1242  {
1243  double wlnv = xyzdat[ jd ].x();
1244  double conv = cvect [ ii ];
1245 
1246  p3dxyz << QVector3D( wlnv, sedv, conv );
1247  }
1248  }
1249 
1250  // Open a 3D plot or reference an opened one, then send data
1251  if ( p3d_ctld == NULL )
1252  {
1253  p3d_pltw = NULL;
1254  p3d_ctld = new US_MwlSPlotControl( this, &p3dxyz );
1255  p3d_ctld->show();
1256  // Position near the upper right of the desktop
1257  int cx = qApp->desktop()->width() - p3d_ctld->width() - 40;
1258  int cy = 40;
1259  p3d_ctld->move( cx, cy );
1260  connect( p3d_ctld, SIGNAL( has_closed() ),
1261  this, SLOT ( p3dctrl_closed() ) );
1262  }
1263 
1264  else
1265  {
1266  p3d_ctld->setFocus();
1267  p3d_ctld->do_3dplot();
1268 
1269  p3d_pltw = p3d_ctld->widget_3dplot();
1270 
1271  if ( p3d_pltw != NULL )
1272  {
1273  p3d_pltw->reloadData( &p3dxyz );
1274 
1275  QString ptitle = tr( "MWL 3-D Plot, Spectra" );
1276 
1277  p3d_pltw->setPlotTitle( ptitle );
1278  p3d_pltw->replot();
1279  }
1280  }
1281 
1282 }
1283 
1284 // Slot to save the current plot
1286 {
1287 DbgLv(1) << "Save Plot";
1288  QString savedir = US_Settings::reportDir() + "/" + runID;
1289  QDir().mkpath( savedir );
1290  savedir = savedir.replace( "\\", "/" ) + "/";
1291  QString fname2d = runID + ".SSpectra_sedRec_RRRRR_2D.png";
1292  QString fname3d = runID + ".SSpectra_3D.png";
1293  p3d_pltw = ( p3d_ctld == NULL ) ? NULL : p3d_ctld->widget_3dplot();
1294  int nfiles = ( p3d_pltw != NULL ) ? 2 : 1;
1295 
1296  if ( nfiles == 2 )
1297  { // If there is a 3D window, first save a PNG of that window
1298 
1299  p3d_pltw->replot(); // Do the plot
1300  QString fpath3d = savedir + fname3d;
1301 
1302  p3d_pltw->save_plot( fpath3d, QString( "png" ) );
1303  }
1304 
1305  // Always save a PNG of the 2-D plot
1306  QString rec_str = cb_pltrec->currentText().replace( ".", "p" );
1307  fname2d = fname2d.replace( "RRRRR", rec_str );
1308  QString fpath2d = savedir + fname2d;
1309 
1310  US_GuiUtil::save_png( fpath2d, data_plot );
1311 
1312  // Report the file(s) saved
1313  QString mtitle = ( nfiles == 1 )
1314  ? tr( "Plot File Saved" )
1315  : tr( "Plot Files Saved" );
1316  QString msg = tr( "In the directory\n %1,\n\n" ).arg( savedir );
1317  if ( nfiles == 1 )
1318  msg += tr( "File\n %1 was saved." ).arg( fname2d );
1319  else
1320  msg += tr( "Files\n %1 ; and\n %2\nwere saved." )
1321  .arg( fname3d ).arg( fname2d );
1322 
1323  QMessageBox::information( this, mtitle, msg );
1324 }
1325 
1326 // Slot to save the current movie
1328 {
1329 DbgLv(1) << "Save 2D Movie";
1330  // Loop to plot each record in the cell and save an image to file
1331  int krecs = cb_pltrec->count();
1332  int svrec = recx; // Save currently plotted record
1333  QStringList fnames;
1334  QString savedir = US_Settings::reportDir() + "/" + runID;
1335  QDir().mkpath( savedir );
1336  savedir = savedir.replace( "\\", "/" ) + "/";
1337  QString bfname = runID + ".2D_frame_XXXXX.png";
1338  QString bstat = tr( "Of %1 records, saving frame " ).arg( krecs );
1339  le_status->setText( bstat );
1340 
1341  for ( int prx = 0; prx < krecs; prx++ )
1342  {
1343  cb_pltrec->setCurrentIndex( prx ); // Plot each record in the range
1344  qApp->processEvents();
1345 
1346  QString frm_str = QString().sprintf( "%05d", ( prx + 1 ) );
1347  QString fname = QString( bfname ).replace( "XXXXX", frm_str );
1348  QString fpath = savedir + fname;
1349 
1350  le_status->setText( bstat + frm_str );
1351 
1352  US_GuiUtil::save_png( fpath, data_plot );
1353  fnames << fname;
1354  }
1355 
1356  cb_pltrec->setCurrentIndex( svrec ); // Restore previous plot record
1357  qApp->processEvents();
1358 
1359  QMessageBox::information( this, tr( "Frame Files Saved" ),
1360  tr( "In the directory\n %1,\n\n%2 2-D movie frame files"
1361  " were saved:\n %3\n ...\n %4 ." )
1362  .arg( savedir ).arg( krecs ).arg( fnames[ 0 ] )
1363  .arg( fnames[ krecs - 1 ] ) );
1364 }
1365 
1366 // Utility to find an index in a QVector<double> to a value epsilon match
1367 int US_MwlSpectra::dvec_index( QVector< double >& dvec, const double dval )
1368 {
1369  const double eps = 1.e-4;
1370 
1371  int indx = dvec.indexOf( dval ); // Try to find an exact match
1372 
1373  if ( indx < 0 )
1374  { // If no exact match was found, look for a match within epsilon
1375 
1376  for ( int jj = 0; jj < dvec.size(); jj++ )
1377  { // Search doubles vector
1378  double ddif = qAbs( dvec[ jj ] - dval );
1379 
1380  if ( ddif < eps )
1381  { // If vector value matches within epsilon, break and return
1382  indx = jj;
1383  break;
1384  }
1385  }
1386  }
1387 
1388  return indx;
1389 }
1390 
1391 // Utility to flag if two doubles are "virtually" equal
1392 bool US_MwlSpectra::dvirt_equal( const double d1, const double d2)
1393 {
1394  const double eps = 1.e-4;
1395 
1396  return ( qAbs( ( d1 - d2 ) / d2 ) < eps );
1397 }
1398 
1399 // Slot to handle the close of the 3D plot control dialog
1401 {
1402  p3d_ctld = NULL;
1403  p3d_pltw = NULL;
1404 }
1405 
1406 // Reset Disk/DB controls whenever the data source is changed in any dialog
1408 {
1409  if ( isDB )
1410  dkdb_cntrls->set_db();
1411  else
1412  dkdb_cntrls->set_disk();
1413 }
1414 
1415 // Utility to compute statistics for all or specific record
1416 void US_MwlSpectra::bld_stats( double wlnv, double sedv, double conv,
1417  QVector< int >& istats, QVector< double >& dstats,
1418  QVector< double >& lwlns, QVector< double >& lseds,
1419  QVector< double >& lcons )
1420 {
1421  if ( conv == 0.0 ) return;
1422 
1423  // Bump non-zero count and counts of sed,lmb
1424  istats[ 0 ]++;
1425  istats[ 1 ] += lwlns.contains( wlnv ) ? 0 : 1;
1426  istats[ 2 ] += lseds.contains( sedv ) ? 0 : 1;
1427 
1428  // Get concentration min,max and accumulate sums for means
1429  dstats[ 0 ] = ( istats[ 0 ] == 1 ) ? conv : qMin( dstats[ 0 ], conv );
1430  dstats[ 1 ] = ( istats[ 0 ] == 1 ) ? conv : qMax( dstats[ 1 ], conv );
1431  dstats[ 2 ] += wlnv;
1432  dstats[ 3 ] += sedv;
1433  dstats[ 4 ] += conv;
1434 
1435  // Accumulate weighted sums
1436  dstats[ 5 ] += ( wlnv * conv );
1437  dstats[ 6 ] += ( sedv * conv );
1438 
1439  // Add values to record lists
1440  lwlns << wlnv;
1441  lseds << sedv;
1442  lcons << conv;
1443 }
1444 
1445 // Utility to finalize statistical computations for a record
1446 void US_MwlSpectra::final_stats( QVector< int >& istats,
1447  QVector< double >& dstats, QVector< double >& lwlns,
1448  QVector< double >& lseds, QVector< double >& lcons )
1449 {
1450  // istats 0-2: nnz, nwvl, nsed
1451  // dstats 0-4: minc, maxc, wmean, smean, cmean,
1452  // 5-9: wwavg, swavg, mediw, medis, medic
1453 
1454  // Complete averages
1455  double dnnz = (double)istats[ 0 ];
1456  double ctot = dstats[ 4 ];
1457  dstats[ 2 ] /= dnnz;
1458  dstats[ 3 ] /= dnnz;
1459  dstats[ 4 ] /= dnnz;
1460  dstats[ 5 ] /= ctot;
1461  dstats[ 6 ] /= ctot;
1462 
1463  // Sort value lists and compute medians
1464  qSort( lwlns );
1465  qSort( lseds );
1466  qSort( lcons );
1467  dstats[ 7 ] = lwlns[ lwlns.count() / 2 ];
1468  dstats[ 8 ] = lseds[ lseds.count() / 2 ];
1469  dstats[ 9 ] = lcons[ lcons.count() / 2 ];
1470 }
1471