UltraScan III
us_vhw_combine.cpp
Go to the documentation of this file.
1 
3 #include <QApplication>
4 
5 #include "us_vhw_combine.h"
6 #include "us_select_runid.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_gui_util.h"
12 #include "us_matrix.h"
13 #include "us_constants.h"
14 #include "us_passwd.h"
15 #include "us_report.h"
16 #include "us_util.h"
17 #include "qwt_legend.h"
18 
19 // main program
20 int main( int argc, char* argv[] )
21 {
22  QApplication application( argc, argv );
23 
24  #include "main1.inc"
25 
26  // License is OK. Start up.
27 
29  w.show();
30  return application.exec();
31 }
32 
33 // US_vHW_Combine class constructor
35 {
36  // set up the GUI (mostly handled in US_AnalysisBase)
37 
38  setWindowTitle( tr( "Combined van Holde - Weischet Distributions:" ) );
39  setPalette( US_GuiSettings::frameColor() );
41  p3d_ctld = NULL;
42  p3d_pltw = NULL;
43 
44  QBoxLayout* mainLayout = new QHBoxLayout( this );
45  QGridLayout* leftLayout = new QGridLayout;
46  QVBoxLayout* rightLayout = new QVBoxLayout;
47  mainLayout ->setSpacing ( 2 );
48  mainLayout ->setContentsMargins( 2, 2, 2, 2 );
49  leftLayout ->setSpacing ( 0 );
50  leftLayout ->setContentsMargins( 0, 1, 0, 1 );
51  rightLayout->setSpacing ( 0 );
52  rightLayout->setContentsMargins( 0, 1, 0, 1 );
53 
56  QPushButton* pb_loadda = us_pushbutton( tr( "Load Data" ) );
57  pb_saveda = us_pushbutton( tr( "Save Data" ) );
58  pb_resetd = us_pushbutton( tr( "Reset Data" ) );
59  pb_resetp = us_pushbutton( tr( "Reset Plot" ) );
60  pb_plot3d = us_pushbutton( tr( "Plot in 3D" ) );
61  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
62  QPushButton* pb_close = us_pushbutton( tr( "Close" ) );
63 
64  pb_saveda->setEnabled( false );
65  pb_resetd->setEnabled( false );
66  pb_resetp->setEnabled( false );
67  pb_plot3d->setEnabled( false );
68 
69  QLabel* lb_distrtype = us_banner(
70  tr( "Select Distribution Plot Type(s):" ) );
71  QLabel* lb_runinfo = us_banner( tr( "Information for this Run:" ) );
72  QLabel* lb_runid = us_label ( tr( "Current Run ID:" ) );
73  QLabel* lb_svproj = us_label ( tr( "Save Plot under Project:" ) );
74  QLabel* lb_runids = us_banner( tr( "Run IDs:" ) );
75  QLabel* lb_triples = us_banner( tr( "Cell / Channel / Wavelength:" ) );
76 
77  QLayout* lo_distrib = us_checkbox( tr( "Integral" ), ck_distrib, true );
78  QLayout* lo_envelope = us_checkbox( tr( "Envelope" ), ck_envelope, false );
79  QLayout* lo_intconc = us_checkbox( tr( "Use Integ.Concentrations" ),
80  ck_intconc, true );
81 
82  le_runid = us_lineedit( "(current run ID)", -1, true );
86  lw_runids->addItem( "" );
87 
88  int row = 0;
89  leftLayout->addLayout( dkdb_cntrls, row++, 0, 1, 8 );
90  leftLayout->addWidget( pb_loadda, row, 0, 1, 4 );
91  leftLayout->addWidget( pb_saveda, row++, 4, 1, 4 );
92  leftLayout->addWidget( pb_resetd, row, 0, 1, 4 );
93  leftLayout->addWidget( pb_resetp, row++, 4, 1, 4 );
94  leftLayout->addWidget( pb_plot3d, row, 0, 1, 4 );
95  leftLayout->addWidget( pb_help, row, 4, 1, 2 );
96  leftLayout->addWidget( pb_close, row++, 6, 1, 2 );
97  leftLayout->addWidget( lb_distrtype, row++, 0, 1, 8 );
98  leftLayout->addLayout( lo_distrib, row, 0, 1, 2 );
99  leftLayout->addLayout( lo_envelope, row, 2, 1, 2 );
100  leftLayout->addLayout( lo_intconc, row++, 4, 1, 4 );
101  leftLayout->addWidget( lb_runinfo, row++, 0, 1, 8 );
102  leftLayout->addWidget( lb_runid, row, 0, 1, 3 );
103  leftLayout->addWidget( le_runid, row++, 3, 1, 5 );
104  leftLayout->addWidget( lb_svproj, row, 0, 1, 3 );
105  leftLayout->addWidget( cmb_svproj, row++, 3, 1, 5 );
106  leftLayout->addWidget( lb_runids, row++, 0, 1, 8 );
107  leftLayout->addWidget( lw_runids, row, 0, 1, 8 );
108  leftLayout->setRowStretch( row, 1 );
109  row += 1;
110  leftLayout->addWidget( lb_triples, row++, 0, 1, 8 );
111  leftLayout->addWidget( lw_triples, row, 0, 7, 8 );
112  leftLayout->setRowStretch( row, 7 );
113  row += 7;
114 
115  connect( dkdb_cntrls, SIGNAL( changed( bool ) ),
116  this, SLOT( update_disk_db( bool ) ) );
117 
118  connect( pb_loadda, SIGNAL( clicked() ),
119  this, SLOT( load() ) );
120  connect( pb_saveda, SIGNAL( clicked() ),
121  this, SLOT( save() ) );
122  connect( pb_resetd, SIGNAL( clicked() ),
123  this, SLOT( reset_data() ) );
124  connect( pb_resetp, SIGNAL( clicked() ),
125  this, SLOT( reset_plot() ) );
126  connect( pb_plot3d, SIGNAL( clicked() ),
127  this, SLOT( plot_3d() ) );
128  connect( pb_help, SIGNAL( clicked() ),
129  this, SLOT( help() ) );
130  connect( pb_close, SIGNAL( clicked() ),
131  this, SLOT( close() ) );
132 
133  connect( ck_distrib, SIGNAL( stateChanged( int) ),
134  this, SLOT( plot_data() ) );
135  connect( ck_envelope, SIGNAL( stateChanged( int) ),
136  this, SLOT( plot_data() ) );
137  connect( ck_intconc, SIGNAL( stateChanged( int) ),
138  this, SLOT( plot_data() ) );
139 
140  connect( lw_runids, SIGNAL( currentRowChanged( int ) ),
141  this, SLOT( runid_select( int ) ) );
142  connect( lw_triples, SIGNAL( currentRowChanged( int ) ),
143  this, SLOT( triple_select( int ) ) );
144 
145  QBoxLayout* plot = new US_Plot( data_plot1,
146  tr( "G(s) Distributions" ),
147  tr( "Sedimentation Coefficient x 1e+13 (corr. for 20,W)" ),
148  tr( "Boundary Fraction (%)" ) );
149 
150 // QString etitle = tr( "Relative Frequency" );
151  QString etitle = tr( "Signal Concentration" );
152  QwtText qtitle( etitle );
153  qtitle.setFont( QFont( US_GuiSettings::fontFamily(),
154  US_GuiSettings::fontSize(), QFont::Bold ) );
155  qtitle.setText( etitle );
156 
157  data_plot1->setMinimumSize( 640, 400 );
158  data_plot1->enableAxis ( QwtPlot::yRight, true );
159  data_plot1->enableAxis ( QwtPlot::yLeft, true );
160  data_plot1->enableAxis ( QwtPlot::xBottom, true );
161  data_plot1->setAxisScale( QwtPlot::xBottom, 1.0, 10.0 );
162  data_plot1->setAxisScale( QwtPlot::yLeft, 0.0, 100.0 );
163  data_plot1->setAxisScale( QwtPlot::yRight, 0.0, 6.0 );
164  data_plot1->setAxisTitle( QwtPlot::yRight, qtitle );
165  QwtPlotGrid* grid = us_grid( data_plot1 );
166  grid->enableXMin( true );
167  grid->enableYMin( true );
168  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
169  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
170 
171  QwtLegend *legend = new QwtLegend;
172  legend->setFrameStyle( QFrame::Box | QFrame::Sunken );
173  legend->setFont( QFont( US_GuiSettings::fontFamily(),
174  US_GuiSettings::fontSize() - 1 ) );
175  data_plot1->insertLegend( legend, QwtPlot::BottomLegend );
176 
177  rightLayout->addLayout( plot );
178 
179  mainLayout ->addLayout( leftLayout );
180  mainLayout ->addLayout( rightLayout );
181  mainLayout ->setStretchFactor( leftLayout, 2 );
182  mainLayout ->setStretchFactor( rightLayout, 5 );
183 
184  le_runid ->setText( "(current run ID)" );
185  cmb_svproj ->addItem( "(project name for plot save)" );
186 
187  adjustSize();
188  int hh = lb_svproj->height();
189  int ww = lb_svproj->width() / 3;
190  lw_runids ->setMinimumHeight( hh * 2 );
191  lw_triples ->setMinimumHeight( hh * 7 );
192  cmb_svproj ->setMinimumWidth ( ww * 5 );
193  for ( int ii = 0; ii < 8; ii++ )
194  leftLayout ->setColumnMinimumWidth( ii, ww );
195  leftLayout ->setColumnStretch ( 0, 1 );
196  leftLayout ->setColumnStretch ( 1, 1 );
197  adjustSize();
198  ww = lw_runids->width();
199  lw_runids ->resize( ww, hh * 2 );
200  adjustSize();
201 
202  reset_data();
203 }
204 
205 // Load data
207 {
208  QStringList runids;
209  QString runid;
210 
211  // Open a dialog and get the runID(s)
212  US_SelectRunid srdiag( dkdb_cntrls->db(), runids );
213  connect( &srdiag, SIGNAL( changed( bool ) ),
214  this, SLOT( update_disk_db( bool ) ) );
215  srdiag.exec();
216 
217  int nruns = runids.size();
218  if ( nruns < 1 ) return;
219 DbgLv(1) << "Selected runIDs[0]" << runids[0] << "count" << nruns;
220 
221  if ( dkdb_cntrls->db() )
222  { // Plot reports are in the database
223  US_Passwd pw;
224  US_DB2 db( pw.getPasswd() );
225 
226  QString tmpdir = US_Settings::tmpDir();
227  US_Report freport;
228  le_runid->setText( tr( "starting data load ..." ) );
229  qApp->processEvents();
230 
231  for ( int ii = 0; ii < nruns; ii++ )
232  {
233  runid = runids[ ii ];
234  freport.readDB( runid, &db );
235  int ntripl = freport.triples.count();
236  int distx = distros.size();
237 DbgLv(1) << " ii,runid,ntrip,dists" << ii << runid << ntripl << distx;
238 
239  for ( int jj = 0; jj < ntripl; jj++ )
240  {
241  US_Report::ReportTriple* tripl = &freport.triples[ jj ];
242  QString trname = collapsedTriple( tripl->triple );
243  int ndocs = tripl->docs.count();
244 DbgLv(1) << " jj,ndocs" << jj << ndocs;
245  le_runid->setText( tr( "loading triple %1 of %2 from run %3" )
246  .arg( jj + 1 ).arg( ntripl ).arg( runid ) );
247  qApp->processEvents();
248  bool havedis = false;
249  bool haveenv = false;
250  US_Report::ReportDocument* ddoc = NULL;
251  US_Report::ReportDocument* edoc = NULL;
252  QString dpath;
253  QString epath;
254 
255  for ( int kk = 0; kk < ndocs; kk++ )
256  {
257  US_Report::ReportDocument* doc = &tripl->docs[ kk ];
258  QString fname = doc->filename;
259 DbgLv(1) << " kk,fname" << kk << fname;
260 
261  if ( fname.contains( "s-c-distrib.csv" ) )
262  {
263  ddoc = doc;
264  dpath = tmpdir + "/" + runid + "." + fname;
265  int stat = db.readBlobFromDB( dpath,
266  QString( "download_reportContents" ), ddoc->documentID );
267 DbgLv(1) << " readBlob stat" << stat;
268 DbgLv(1) << " dpath" << dpath;
269 
270  if ( stat != US_DB2::OK )
271  {
272  qDebug() << "*ERROR* download_reportContents" << stat;
273  qDebug() << " DPATH" << dpath;
274  havedis = false;
275  }
276  else
277  havedis = true;
278  }
279 
280  else if ( fname.contains( "s-c-envelope.csv" ) )
281  {
282  edoc = doc;
283  epath = tmpdir + "/" + runid + "." + fname;
284 DbgLv(1) << " epath" << epath;
285  int stat = db.readBlobFromDB( epath,
286  QString( "download_reportContents" ), edoc->documentID );
287 DbgLv(1) << " readBlob stat" << stat;
288 
289  if ( stat != US_DB2::OK )
290  {
291  qDebug() << "*ERROR* download_reportContents" << stat;
292  qDebug() << " EPATH" << epath;
293  haveenv = false;
294  }
295  else
296  haveenv = true;
297  }
298  } // END: documents loop
299 
300  if ( havedis )
301  {
302  QString fname = dpath.section( "/", -1, -1 );
303  DistrDesc ddesc;
304  ddesc.runID = runid;
305  ddesc.triple = trname;
306 DbgLv(1) << " havedis run trip" << runid << tripl << "haveenv" << haveenv;
307 DbgLv(1) << " dpath" << dpath;
308 DbgLv(1) << " epath" << epath;
309  QFile fid( dpath );
310 
311  if ( fid.open( QIODevice::ReadOnly | QIODevice::Text ) )
312  {
313  QTextStream tsd( &fid );
314  QTextStream tse;
315  QFile fie( epath );
316  if ( haveenv &&
317  fie.open( QIODevice::ReadOnly | QIODevice::Text ) )
318  tse.setDevice( &fie );
319  else
320  haveenv = false;
321 
322  fill_in_desc( tsd, tse, ddesc, haveenv, distx );
323 
324 
325  distros << ddesc;
326  distIDs << runid + "." + trname;
327  distx++;
328  fid.close();
329  if ( haveenv )
330  fie.close();
331  }
332  }
333  } // END: triples loop
334  } // END: runids loop
335  }
336 
337  else
338  { // Plot reports are on local disk
339 
340  QString resdir = US_Settings::resultDir() + "/";
341 
342  for ( int ii = 0; ii < nruns; ii++ )
343  {
344  runid = runids[ ii ];
345  QString rundir = resdir + runid + "/";
346 
347  QStringList datfilt( "vHW.*s-c-distrib.csv" );
348  QStringList dfiles = QDir( rundir )
349  .entryList( datfilt, QDir::Files, QDir::Name );
350 
351  int distx = distros.size();
352  int ndfile = dfiles.count();
353 
354  if ( ndfile == 0 )
355  {
356  QMessageBox::information( this, tr( "No Distribution Plots" ),
357  tr( "The selected Run ID Directory\n %1\n"
358  "contained no vHW distribution plots." )
359  .arg( rundir ) );
360  }
361 
362  for ( int ii = 0; ii < ndfile; ii++ )
363  {
364  QString fname = dfiles[ ii ];
365  QString fpath = rundir + "/" + fname;
366  QString epath = QString( fpath ).replace( "distrib.csv",
367  "envelope.csv" );
368  QString tripl = fname.section( ".", 1, 1 );
369  DistrDesc ddesc;
370  ddesc.runID = runid;
371  ddesc.triple = tripl;
372  QFile fid( fpath );
373 
374  if ( fid.open( QIODevice::ReadOnly | QIODevice::Text ) )
375  {
376  QTextStream tsd( &fid );
377  QTextStream tse;
378  QFile fie( epath );
379  bool haveenv = fie.open( QIODevice::ReadOnly | QIODevice::Text );
380  if ( haveenv )
381  tse.setDevice( &fie );
382 
383  fill_in_desc( tsd, tse, ddesc, haveenv, distx );
384 
385 
386  distros << ddesc;
387  distIDs << runid + "." + tripl;
388  distx++;
389  fid.close();
390  if ( haveenv )
391  fie.close();
392  }
393  }
394  }
395  }
396 
397  int nrunids = runids.count();
398  int nsprojs = cmb_svproj->count();
399 
400  if ( nsprojs == 1 )
401  cmb_svproj->clear();
402  else
403  cmb_svproj->removeItem( nsprojs - 1 );
404 
405  for ( int ii = 0; ii < nrunids; ii++ )
406  {
407  lw_runids->addItem( runids[ ii ] );
408  cmb_svproj->addItem( runids[ ii ] );
409  }
410 
411  cmb_svproj->addItem( "All" );
412 
413  int nlitems = lw_runids->count();
414  le_runid->setText( runids[ 0 ] );
415 
416  if ( nrunids == nlitems )
417  {
418  adjustSize();
419  }
420 
421  pb_resetd->setEnabled( true );
422 }
423 
424 // Reset data: remove all loaded data and clear plots
426 {
427  distros.clear();
428  distIDs.clear();
429 
430  lw_runids ->clear();
431  lw_triples ->clear();
432  le_runid ->clear();
433  cmb_svproj ->clear();
434 
435  reset_plot();
436 
437  pb_resetd->setEnabled( false );
438  pb_resetp->setEnabled( false );
439  pb_plot3d->setEnabled( false );
440 }
441 
442 // Reset plot: Clear plots and lists of plotted data
444 {
445  data_plot1->detachItems();
446  data_plot1->clear();
447  data_plot1->replot();
448 
449  pdistrs.clear();
450  pdisIDs.clear();
451  pb_saveda->setEnabled( false );
452 
453  lw_triples ->setCurrentRow( -1 );
454 }
455 
456 // Plot all data
458 {
459  data_plot1->detachItems();
460  QwtPlotGrid* grid = us_grid( data_plot1 );
461  grid->enableXMin( true );
462  grid->enableYMin( true );
463  grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(), 0, Qt::DashLine ) );
464  grid->setMinPen( QPen( US_GuiSettings::plotMinGrid(), 0, Qt::DotLine ) );
465 
466  bool dplot = ck_distrib ->isChecked();
467  bool eplot = ck_envelope->isChecked();
468  ck_intconc->setEnabled( dplot );
469  QString ptitle = tr( "G(s) Distributions" );
470 
471  if ( dplot && eplot )
472  {
473  ptitle = tr( "G(s)/g(s) Distributions" );
474  }
475  else if ( dplot )
476  {
477  ptitle = tr( "G(s) Distributions" );
478  }
479  else if ( eplot )
480  {
481  ptitle = tr( "g(s) Distributions" );
482  }
483 
484  data_plot1->setTitle( ptitle );
485 
486  for ( int ii = 0; ii < pdistrs.size(); ii++ )
487  plot_distr( pdistrs[ ii ], pdisIDs[ ii ] );
488 }
489 
490 // Add a single distribution to the plot
491 void US_vHW_Combine::plot_distr( DistrDesc ddesc, QString distrID )
492 {
493  QVector< double > dconcs;
494  bool dplot = ck_distrib ->isChecked();
495  bool eplot = ck_envelope->isChecked();
496  bool dconc = ck_intconc ->isChecked();
497  int ndispt = ddesc.bfracs.size();
498  int nenvpt = ddesc.efreqs.size();
499  double* xx = ddesc.dsedcs.data();
500  double* yy = ddesc.bfracs.data();
501  double* xs = ddesc.esedcs.data();
502  double* yf = ddesc.efreqs.data();
503  double fscl = dconc ? ( ddesc.totconc * 0.01 ) : 1.0;
504 
505  QString dcID = distrID + tr( " (integ.)" );
506  QString ecID = distrID + tr( " (diff.)" );
507  QwtPlotCurve* dcurve;
508  QwtPlotCurve* ecurve;
509  QPen dlpen( QPen( Qt::yellow ) );
510  QPen elpen( QPen( QBrush( ddesc.color ), 3.0 ) );
511 
512  if ( dplot && !dconc )
513  { // Build curves for distribution plot
514  dcurve = us_curve( data_plot1, dcID );
515  dcurve->setStyle ( QwtPlotCurve::Lines );
516  dcurve->setSymbol( ddesc.symbol );
517  dcurve->setPen ( dlpen );
518  dcurve->setData ( xx, yy, ndispt );
519  dcurve->setYAxis ( QwtPlot::yLeft );
520  }
521 
522  if ( dplot && dconc )
523  { // Build curves for integration/concentration plot
524  dconcs.clear();
525  dconcs.reserve( ndispt );
526 
527  for ( int ii = 0; ii < ndispt; ii++ )
528  dconcs << ( yy[ ii ] * fscl );
529 
530  double* yc = dconcs.data();
531  dcurve = us_curve( data_plot1, dcID );
532  dcurve->setStyle ( QwtPlotCurve::Lines );
533  dcurve->setSymbol( ddesc.symbol );
534  dcurve->setPen ( dlpen );
535  dcurve->setData ( xx, yc, ndispt );
536  dcurve->setYAxis ( QwtPlot::yRight );
537  }
538 
539  if ( eplot )
540  { // Build curve for envelope plot
541 int kk=ddesc.efreqs.size();
542 DbgLv(2) << " xs0 yf0" << xs[0] << yf[0];
543 DbgLv(2) << " xs1 yf1" << xs[1] << yf[1];
544 DbgLv(2) << " xsm yfm" << xs[kk-2] << yf[kk-2];
545 DbgLv(2) << " xsn yfn" << xs[kk-1] << yf[kk-1];
546  ecurve = us_curve( data_plot1, ecID );
547  ecurve->setStyle ( QwtPlotCurve::Lines );
548  ecurve->setPen ( elpen );
549  ecurve->setData ( xs, yf, nenvpt );
550  ecurve->setYAxis ( QwtPlot::yRight );
551  }
552 
553  data_plot1->setAxisAutoScale( QwtPlot::xBottom );
554  data_plot1->setAxisAutoScale( QwtPlot::yLeft );
555  data_plot1->setAxisAutoScale( QwtPlot::yRight );
556  data_plot1->enableAxis ( QwtPlot::yLeft, dplot && ! dconc );
557  data_plot1->enableAxis ( QwtPlot::yRight, eplot || dconc );
558 
559  data_plot1->replot();
560 }
561 
562 // Save the plot data
564 {
565  QString oproj = cmb_svproj->currentText();
566  QString runID = ( oproj == "All" ) ? pdistrs[ 0 ].runID : oproj;
567  QString trname = pdistrs[ 0 ].triple;
568  QString fdir = US_Settings::reportDir() + "/" + runID;
569  QString fnamsvg = "vHW.0Z9999.combo-distrib.svgz";
570  QString fnampng = "vHW.0Z9999.combo-distrib.png";
571  QString fnamdat = "vHW.0Z9999.combo-sb-distrib.csv";
572  QString fnamenv = "vHW.0Z9999.combo-s-envelope.csv";
573  QString fnamlst = "vHW.0Z9999.combo-list-include.rpt";
574  QString plotFile = fdir + "/" + fnamsvg;
575  QString dataFile = fdir + "/" + fnamdat;
576  QString denvFile = fdir + "/" + fnamenv;
577  QString listFile = fdir + "/" + fnamlst;
578  QStringList prunids;
579  QList< int > prndxs;
580  QString svmsg = tr( "Saved:\n " ) + fnampng + "\n "
581  + fnamsvg + "\n "
582  + fnamdat + "\n "
583  + fnamenv + "\n "
584  + fnamlst + "\n";
585  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
586 
587  // Look for multiple run IDs
588  for ( int ii = 0; ii < pdistrs.size(); ii++ )
589  {
590  QString prun = pdistrs[ ii ].runID;
591  if ( oproj == "All" )
592  { // If save-plot project is "All", save lists of runids and indexes
593  if ( ! prunids.contains( prun ) )
594  {
595  prunids << prun;
596  prndxs << ii;
597  }
598  }
599 
600  else if ( prun == runID )
601  { // If save-plot project matches current run, save it and its index
602  prunids << prun;
603  prndxs << ii;
604  break;
605  }
606  }
607 
608  int iruns = 0;
609  int nruns = prunids.size();
610  int jdist = 0;
611 
612  while( iruns < nruns )
613  {
614  if ( ! QFile( fdir ).exists() )
615  { // If need be, create runID directory
616  QDir().mkpath( fdir );
617  }
618 
619  // Save plot file as SVG and as PNG; write data and list files
620  write_plot( plotFile, data_plot1 );
621  write_data( dataFile, listFile, iruns );
622  write_denv( denvFile, iruns );
623  svmsg += tr( "in directory:" ) + "\n " + fdir + "\n";
624 
625  if ( dkdb_cntrls->db() )
626  {
627  US_Passwd pw;
628  US_DB2 db( pw.getPasswd() );
629  int idEdit = 0;
630 
631  QString trfirst = pdistrs[ 0 ].triple;
632  QString trlast = pdistrs[ pdistrs.size() - 1 ].triple;
633  QString trdesc = "Combined Analyses (" + trfirst
634  + "..." + trlast + ")";
635 
636  QString editID; // Edit ID for matching experiment,triple
637  QString eeditID; // First edit ID from experiment match
638  // Get test triple to match file part and investigator
639  QString trip1 = US_Util::expanded_triple( trfirst, false )
640  .replace( '/', '.' );
641  QString invID = QString::number( US_Settings::us_inv_ID() );
642  // Query for the experiment ID matching the run ID
643  QStringList query;
644  query << "get_experiment_info_by_runID" << runID << invID;
645  db.query( query );
646  db.next();
647  QString expID = db.value( 1 ).toString();
648 DbgLv(1) << "SV: runID expID" << runID << expID;
649  // Query for the raw ID in experiment matching a triple
650  QString rawID;
651  query.clear();
652  query << "get_rawDataIDs" << expID;
653  db.query( query );
654  while ( db.next() )
655  {
656  rawID = db.value( 0 ).toString();
657  QString efname = db.value( 2 ).toString();
658 DbgLv(1) << "SV: rawID" << rawID << "efname" << efname << "trip1" << trip1;
659  // Save rawID when we have found a triple match
660  if ( efname.contains( trip1 ) )
661  break;
662  }
663  // Query edit IDs for raw ID and look for triple match
664  query.clear();
665  query << "get_editedDataIDs" << rawID;
666  db.query( query );
667  while ( db.next() )
668  {
669  QString aeditID = db.value( 0 ).toString();
670  QString efname = db.value( 2 ).toString();
671  if ( eeditID.isEmpty() )
672  eeditID = aeditID; // Save 1st valid from experiment
673 DbgLv(1) << "SV: editID" << eeditID << "raw exp trip1 fname"
674  << rawID << expID << trip1 << efname;
675  if ( efname.contains( trip1 ) )
676  { // Keep saving editID from last triple match
677  editID = aeditID;
678 DbgLv(1) << "SV: Name-Trip MATCH: editID" << editID;
679  }
680  }
681 
682  if ( ! editID.isEmpty() )
683  { // Use edit ID from last matching triple
684  idEdit = editID.toInt();
685  }
686  else
687  { // Or fall back to one from first valid edit in experiment
688  idEdit = eeditID.toInt();
689  }
690 DbgLv(1) << "SV: editID idEdit" << editID << idEdit << " eeditID" << eeditID;
691 
692  // Add or update report documents in the database
693  QStringList rfiles;
694  rfiles << fnamsvg << fnampng << fnamdat << fnamenv << fnamlst;
695  int st = reportDocsFromFiles( runID, fdir, rfiles, &db,
696  idEdit, trdesc );
697 
698 DbgLv(1) << "SV:runID" << runID << "idEdit" << idEdit
699  << "fnamlst" << fnamlst << "trdesc" << trdesc;
700  if ( iruns == ( nruns - 1 ) )
701  { // Append message line after last run save
702  if ( st == 0 )
703  svmsg += tr( "\nThe files were also saved to the database" );
704  else
705  svmsg += tr( "\n*ERROR* in saving files to the database" );
706  }
707  } // END: database
708 
709  if ( ++iruns >= nruns ) break;
710 
711  runID = prunids[ iruns ];
712  jdist = prndxs [ iruns ];
713  trname = pdistrs[ jdist ].triple;
714  fdir = US_Settings::reportDir() + "/" + runID;
715  plotFile = fdir + "/" + fnamsvg;
716  dataFile = fdir + "/" + fnamdat;
717  denvFile = fdir + "/" + fnamenv;
718  listFile = fdir + "/" + fnamlst;
719  } // END: runs loop
720 
721  QApplication::restoreOverrideCursor();
722 
723  // Report saved files
724  QMessageBox::information( this, tr( "Combo Distro Plot File Save" ), svmsg );
725 }
726 
727 // RunID selected
729 {
730 DbgLv(1) << "RunIDSel:row" << row;
731  if ( row < 0 ) return;
732  QListWidgetItem* item = lw_runids->item( row );
733  runID = item->text();
734 DbgLv(1) << "RunIDSel:runID" << runID << "distrsize" << distros.size();
735  le_runid ->setText( runID );
736 
737  lw_triples->clear();
738 
739  for ( int ii = 0; ii < distros.size(); ii++ )
740  {
741 DbgLv(1) << "RunIDSel: ii runID" << ii << distros[ii].runID;
742  if ( distros[ ii ].runID == runID )
743  {
744  DistrDesc ddesc = distros[ ii ];
745  QString distrID = ddesc.runID + " ("
746  + ddesc.triple + ") : "
747  + ddesc.tdescr;
748  lw_triples->addItem( distrID );
749  }
750  }
751 
752  if ( pdistrs.size() == 0 )
753  {
754  cmb_svproj->setCurrentIndex( cmb_svproj->findText( runID ) );
755  }
756 }
757 
758 // Triple selected
760 {
761 DbgLv(1) << "TripleSel:row" << row;
762  if ( row < 0 ) return;
763  QListWidgetItem* item = lw_triples->item( row );
764  triple = item->text().section( ":", 0, 0 ).right( 7 ).mid( 0, 5 );
765 DbgLv(1) << "TripleSel:triple" << triple;
766 
767  DistrDesc ddesc;
768 
769  for ( int ii = 0; ii < distros.size(); ii++ )
770  {
771  ddesc = distros[ ii ];
772 
773  if ( ddesc.runID == runID && ddesc.triple == triple )
774  break;
775  }
776 
777  QString distrID = ddesc.runID + " (" + ddesc.triple + ") : "
778  + ddesc.tdescr;
779 
780 DbgLv(1) << "TripleSel:distrID" << distrID;
781  if ( ! pdisIDs.contains( distrID ) )
782  {
783 DbgLv(1) << "TripleSel:distrID NEW TO LIST";
784  pdistrs << ddesc;
785  pdisIDs << distrID;
786 
787  plot_distr( ddesc, distrID );
788  }
789 
790  else
791  {
792 DbgLv(1) << "TripleSel:distrID ALREADY IN LIST";
793  plot_data();
794  }
795 
796  pb_saveda->setEnabled( true );
797  pb_resetd->setEnabled( true );
798  pb_resetp->setEnabled( true );
799  pb_plot3d->setEnabled( true );
800 }
801 
802 // Assign symbol and color for a distribution
803 void US_vHW_Combine::setSymbol( DistrDesc& ddesc, int distx )
804 {
805  QwtSymbol dsymbol;
806 
807  possibleSymbols(); // Make sure possible symbols,colors exist
808 
809  int nsymbs = symbols.size();
810  int ncolors = colors.size();
811  int js = distx;
812  int jc = distx;
813 
814  while ( js >= nsymbs )
815  js -= nsymbs;
816 
817  while ( jc >= ncolors )
818  jc -= ncolors;
819 
820  ddesc.color = colors [ jc ];
821  dsymbol.setPen( QColor( Qt::white ) );
822  dsymbol.setSize( 8 );
823  dsymbol.setStyle( (QwtSymbol::Style)symbols[ js ] );
824  dsymbol.setBrush( ddesc.color );
825  ddesc.symbol = dsymbol;
826 
827  return;
828 }
829 
830 // Generate lists of symbol styles and colors if need be
832 {
833  if ( symbols.size() > 0 && colors.size() > 0 )
834  return;
835 
836  symbols.clear();
837  colors .clear();
838 
839  symbols << (int)( QwtSymbol::Ellipse );
840  symbols << (int)( QwtSymbol::Rect );
841  symbols << (int)( QwtSymbol::Triangle );
842  symbols << (int)( QwtSymbol::Diamond );
843  symbols << (int)( QwtSymbol::LTriangle );
844  symbols << (int)( QwtSymbol::Hexagon );
845  symbols << (int)( QwtSymbol::Star2 );
846  symbols << (int)( QwtSymbol::DTriangle );
847 
848  colors << QColor( 255, 0, 0 );
849  colors << QColor( 0, 255, 0 );
850  colors << QColor( 0, 0, 255 );
851  colors << QColor( 255, 255, 0 );
852  colors << QColor( 255, 0, 255 );
853  colors << QColor( 0, 255, 255 );
854  colors << QColor( 122, 0, 255 );
855  colors << QColor( 0, 255, 122 );
856  colors << QColor( 0, 122, 255 );
857  colors << QColor( 255, 122, 0 );
858  colors << QColor( 122, 255, 0 );
859  colors << QColor( 80, 0, 255 );
860  colors << QColor( 255, 0, 80 );
861  colors << QColor( 80, 0, 255 );
862  colors << QColor( 255, 0, 80 );
863  colors << QColor( 0, 255, 80 );
864  colors << QColor( 0, 80, 255 );
865  colors << QColor( 80, 255, 0 );
866  colors << QColor( 255, 80, 40 );
867  colors << QColor( 40, 255, 40 );
868  colors << QColor( 40, 40, 255 );
869 }
870 
871 // Return an expanded version ("1 / A / 260") of a triple string ("1A260")
872 QString US_vHW_Combine::expandedTriple( QString ctriple )
873 {
874  QString etriple = ctriple;
875 
876  if ( ! etriple.contains( " / " ) )
877  etriple = etriple.left( 1 ) + " / " +
878  etriple.mid( 1, 1 ) + " / " +
879  etriple.mid( 2 );
880 
881  return etriple;
882 }
883 
884 // Return a collapsed version ("1A260") of a triple string ("1 / A / 260")
885 QString US_vHW_Combine::collapsedTriple( QString etriple )
886 {
887  QString ctriple = etriple;
888 
889  if ( ctriple.contains( " / " ) )
890  ctriple = ctriple.replace( " / ", "" ).simplified();
891  else if ( ctriple.contains( "/" ) )
892  ctriple = ctriple.replace( "/", "" ).simplified();
893  else if ( ctriple.contains( "." ) )
894  ctriple = ctriple.replace( ".", "" ).simplified();
895 
896  return ctriple;
897 }
898 
899 // Generate envelope data
901 {
902  int nSensit = 50;
903  int nSmooth = 30;
904  int steps;
905  int nepts = 300;
906  int ndpts = ddesc.dsedcs.size();
907  double max_cept = 1.0e-6;
908  double min_cept = 1.0e+6;
909  double sed_bin = ddesc.dsedcs.at( 0 );
910  double his_sum = 0.0;
911  double env_sum = 0.0;
912  double div_scl = (double)nSensit * (double)ndpts * 0.01;
913  double max_step;
914  double sigma;
915  double sed_lo;
916  double sed_hi;
917  double sedc;
918 
919  for ( int jj = 0; jj < ndpts; jj++ )
920  { // get min,max intercept sedimentation coefficients
921  min_cept = qMin( min_cept, ddesc.dsedcs.at( jj ) );
922  max_cept = qMax( max_cept, ddesc.dsedcs.at( jj ) );
923  }
924 
925  // calculate values based on range and sensitivity
926  sed_bin = ( max_cept - min_cept ) / div_scl;
927  max_step = max_cept * 4.0 / 3.0;
928  steps = (int)( max_step / sed_bin );
929 
930  if ( nepts <= steps )
931  { // insure envelope array size bigger than histogram array size
932  nepts = steps + 1;
933  }
934 
935  ddesc.esedcs.fill( 0.0, nepts );
936  ddesc.efreqs.fill( 0.0, nepts );
937  double bink = 0.0;
938  double sval = 0.0;
939  double pisqr = sqrt( M_PI * 2.0 );
940  double* xval = ddesc.esedcs.data();
941  double* yval = ddesc.efreqs.data();
942  double scale = max_step / (double)nepts;
943 
944  for ( int jj = 0; jj < nepts; jj++ )
945  { // initialize envelope values
946  xval[ jj ] = scale * (double)jj;
947  yval[ jj ] = 0.0;
948  }
949 
950  sigma = sed_bin * 0.02 * (double)nSmooth;
951 
952  for ( int jj = 0; jj < steps; jj++ )
953  { // calculate histogram values and envelope values based on them
954  int kbin = 0;
955  sed_lo = sed_bin * (double)jj;
956  sed_hi = sed_lo + sed_bin;
957  sval = ( sed_lo + sed_hi ) * 0.5;
958 
959  for ( int kk = 0; kk < ndpts; kk++ )
960  { // count sedcoeffs within current step range
961  sedc = ddesc.dsedcs.at( kk );
962 
963  if ( sedc >= sed_lo && sedc < sed_hi )
964  kbin++;
965  }
966 
967  bink = (double)kbin;
968  his_sum += ( bink * sed_bin ); // bump histogram sum
969 
970  if ( kbin > 0 )
971  { // if non-empty bin, update envelope Y values
972  for ( int kk = 0; kk < nepts; kk++ )
973  {
974  double xdif = ( xval[ kk ] - sval ) / sigma;
975  yval[ kk ] += ( ( bink / ( sigma * pisqr ) )
976  * exp( -( xdif * xdif ) / 2.0 ) );
977  }
978  }
979  }
980 
981  for ( int kk = 0; kk < nepts; kk++ )
982  { // accumulate the envelope values sum
983  env_sum += yval[ kk ];
984  }
985 
986  env_sum *= xval[ 1 ]; // sum times X increment
987  scale = his_sum / env_sum; // normalizing scale factor
988 DbgLv(2) << "ED: hsum esum scale " << his_sum << env_sum << scale;
989 
990  int fnz = -1;
991  int lnz = 0;
992 
993  for ( int kk = 0; kk < nepts; kk++ )
994  { // normalize Y values
995  yval[ kk ] *= scale;
996 
997  if ( yval[ kk ] != 0.0 )
998  {
999  if ( fnz < 0 ) fnz = kk;
1000  lnz = kk;
1001  }
1002  }
1003 
1004  fnz = qMax( ( fnz - 2 ), 0 );
1005  lnz = qMin( ( lnz + 2 ), nepts );
1006  nepts = 0;
1007 
1008  for ( int ii = fnz; ii < lnz; ii++ )
1009  { // Reduce array to Y's from first to last non-zero
1010  xval[ nepts ] = xval[ ii ];
1011  yval[ nepts ] = yval[ ii ];
1012  nepts++;
1013  }
1014 
1015  ddesc.esedcs.resize( nepts );
1016  ddesc.efreqs.resize( nepts );
1017  ddesc.totconc = 1.0;
1018 
1019  return nepts; // return arrays' size
1020 }
1021 
1022 // Reset Disk_DB control whenever data source is changed in any dialog
1024 {
1025  isDB ? dkdb_cntrls->set_db() : dkdb_cntrls->set_disk();
1026 DbgLv(1) << "Upd_Dk_Db isDB" << isDB;
1027 
1028  reset_data();
1029 }
1030 
1031 void US_vHW_Combine::fill_in_desc( QTextStream& tsd, QTextStream& tse,
1032  DistrDesc& ddesc, bool haveenv, int distx )
1033 {
1034  // Read distribution stream to set sed and bound values
1035  QString fline = tsd.readLine().simplified();
1036 DbgLv(1) << "FID: fline0" << fline;
1037 
1038  if ( fline.contains( "%Boundary" ) )
1039  ddesc.tdescr = tr( "(Unknown description)" );
1040  else
1041  {
1042  ddesc.tdescr = fline;
1043  fline = tsd.readLine();
1044  }
1045  QString str;
1046  while ( !tsd.atEnd() )
1047  {
1048  fline = tsd.readLine().simplified();
1049  //double bound = str.section( ",", 0, 0).toDouble();
1050  str = fline.section( ",", 0, 0);
1051  double bound = str.remove("\"").toDouble();
1052  str = fline.section( ",", 3, 3);
1053  double sedc = str.remove("\"").toDouble();
1054 
1055 //DbgLv(1) << "bound:" << bound << " sedc:" << sedc;
1056 
1057  ddesc.dsedcs << sedc;
1058  ddesc.bfracs << bound;
1059  }
1060 int kk = ddesc.dsedcs.size()-1;
1061 DbgLv(1) << "Distro runid" << ddesc.runID << " triple" << ddesc.triple << kk;
1062 DbgLv(1) << " 0 sed frac" << ddesc.dsedcs[0] << ddesc.bfracs[0];
1063 DbgLv(1) << " kk sed frac" << ddesc.dsedcs[kk] << ddesc.bfracs[kk];
1064  setSymbol( ddesc, distx );
1065 
1066  if ( haveenv )
1067  { // Read in envelope data
1068  fline = tse.readLine();
1069  int fnz = -1;
1070  int lnz = 0;
1071  bool fev = true;
1072 
1073  QString str;
1074  while ( !tse.atEnd() )
1075  {
1076  fline = tse.readLine().simplified();
1077  str = fline.section( ",", 0, 0 );
1078  double sedc = str.remove( "\"" ).toDouble();
1079  str = fline.section( ",", 1, 1 );
1080  double freq = str.remove( "\"" ).toDouble();
1081 
1082  if ( freq != 0.0 )
1083  {
1084  lnz = ddesc.esedcs.size();
1085  if ( fnz < 0 )
1086  {
1087  fnz = lnz;
1088  }
1089  }
1090 
1091  if ( fev )
1092  {
1093  fev = false;
1094  str = fline.section( ",", 4, 4 );
1095  double conc = str.remove( "\"" ).toDouble();
1096  ddesc.totconc = conc;
1097 DbgLv(1) << "TotConc" << ddesc.totconc << "str" << str;
1098 DbgLv(1) << "FLine" << fline;
1099 
1100  if ( conc == 0.0 )
1101  {
1102  QMessageBox::warning( this,
1103  tr( "No Total Concentration" ),
1104  tr( "The Envelope CSV for Run %1 does not contain"
1105  " a Total Concentration value. The vHW application"
1106  " should be re-run to re-create this report." )
1107  .arg( ddesc.runID ) );
1108  }
1109  }
1110 
1111  ddesc.esedcs << sedc;
1112  ddesc.efreqs << freq;
1113  }
1114 
1115  int nepts = ddesc.esedcs.size();
1116  fnz = qMax( ( fnz - 2 ), 0 );
1117  lnz = qMin( ( lnz + 2 ), nepts );
1118  nepts = 0;
1119  double ysum = 0.0;
1120 
1121  for ( int jj = fnz; jj < lnz; jj++ )
1122  { // Reduce array to Y's from first to last non-zero
1123  ddesc.esedcs[ nepts ] = ddesc.esedcs[ jj ];
1124  ddesc.efreqs[ nepts ] = ddesc.efreqs[ jj ];
1125  // Accumulate sum of frequencies
1126  ysum += ddesc.efreqs[ jj ];
1127  nepts++;
1128  }
1129 
1130  double sclf = ( ddesc.totconc == 0.0 ) ? 1.0 : ( ddesc.totconc / ysum );
1131 
1132  // Convert Ys from frequency to concentration
1133  for ( int jj = 0; jj < nepts; jj++ )
1134  ddesc.efreqs[ jj ] *= sclf;
1135 
1136  if ( nepts < ddesc.esedcs.size() )
1137  {
1138  ddesc.esedcs.resize( nepts );
1139  ddesc.efreqs.resize( nepts );
1140  }
1141 DbgLv(1) << " Envel nepts" << nepts << ddesc.esedcs.size();
1142 int kk = ddesc.esedcs.size()-1;
1143 DbgLv(1) << " 0 sed frac" << ddesc.esedcs[0] << ddesc.efreqs[0];
1144 DbgLv(1) << " kk sed frac" << ddesc.esedcs[kk] << ddesc.efreqs[kk];
1145  }
1146 
1147  else
1148  { // Calculate envelope data from distribution data
1149  envel_data( ddesc );
1150  }
1151 }
1152 
1153 // Write data and list report files
1154 void US_vHW_Combine::write_data( QString& dataFile, QString& listFile,
1155  int& irun )
1156 {
1157  if ( irun > 0 )
1158  { // After first/only time: just make a copy of the files
1159  QFile( dat1File ).copy( dataFile );
1160  QFile( lis1File ).copy( listFile );
1161  return;
1162  }
1163 
1164  // First/only time through: compute the data and create files
1165  QStringList pdlong;
1166  QString line;
1167  dat1File = dataFile;
1168  lis1File = listFile;
1169  bool dconc = ck_intconc ->isChecked();
1170 
1171  QFile dfile( dataFile );
1172 
1173  if ( ! dfile.open( QIODevice::WriteOnly | QIODevice::Text ) )
1174  {
1175  qDebug() << "***Error opening output file" << dataFile;
1176  return;
1177  }
1178 
1179  QTextStream tsd( &dfile );
1180 
1181  int nplots = pdistrs.size();
1182  int lastp = nplots - 1;
1183  int maxnvl = 0;
1184  line = "";
1185 
1186  for ( int ii = 0; ii < nplots; ii++ )
1187  { // Accumulate long descriptions and build header line
1188  maxnvl = qMax( maxnvl, pdistrs[ ii ].dsedcs.size() );
1189  QString pd = pdisIDs[ ii ];
1190  pdlong << pd;
1191  pd = pd.section( ":", 0, 0 ).simplified();
1192  line += "\"" + pd + ".X\",\"" + pd + ".Y\""; // X,Y header entries for contributor
1193 
1194  if ( ii < lastp )
1195  line += ",";
1196  else
1197  line += "\n";
1198  }
1199  tsd << line; // Write header line
1200 
1201  for ( int jj = 0; jj < maxnvl; jj++ )
1202  { // Build and write svalue+boundary data line
1203  line = "";
1204  for ( int ii = 0; ii < nplots; ii++ )
1205  { // Add each X,Y data pair
1206  double bscl = dconc ? ( pdistrs[ ii ].totconc * 0.01 ) : 1.0;
1207  int nvals = pdistrs[ ii ].dsedcs.size();
1208  double* xx = pdistrs[ ii ].dsedcs.data();
1209  double* yy = pdistrs[ ii ].bfracs.data();
1210  int kk = qMin( jj, ( nvals - 1 ) );
1211  double sval = xx[ kk ];
1212  double boun = yy[ kk ] * bscl;
1213 
1214  QString dat = QString().sprintf( "\"%12.5f\",\"%10.5f\"", sval, boun );
1215  dat.replace( " ", "" );
1216  line += dat;
1217 
1218  if ( ii < lastp )
1219  line += ",";
1220  else
1221  line += "\n";
1222  }
1223  tsd << line; // Write data line
1224  }
1225 
1226  dfile.close();
1227 
1228  // Write list-of-included file
1229  QFile lfile( listFile );
1230  if ( ! lfile.open( QIODevice::WriteOnly | QIODevice::Text ) )
1231  {
1232  qDebug() << "***Error opening output file" << listFile;
1233  return;
1234  }
1235  QTextStream tsl( &lfile );
1236 
1237  for ( int ii = 0; ii < nplots; ii++ )
1238  { // Build and write each long-description line
1239  line = pdlong[ ii ] + "\n";
1240  tsl << line;
1241  }
1242 
1243  lfile.close();
1244 
1245  return;
1246 }
1247 
1248 // Write data envelope report file
1249 void US_vHW_Combine::write_denv( QString& denvFile, int& irun )
1250 {
1251  if ( irun > 0 )
1252  { // After first/only time: just make a copy of the file
1253  QFile( env1File ).copy( denvFile );
1254  return;
1255  }
1256 
1257  // First/only time through: compute the data and create files
1258  QStringList pdlong;
1259  QString line;
1260  env1File = denvFile;
1261 
1262  QFile dfile( denvFile );
1263 
1264  if ( ! dfile.open( QIODevice::WriteOnly | QIODevice::Text ) )
1265  {
1266  qDebug() << "***Error opening output file" << denvFile;
1267  return;
1268  }
1269 
1270  QTextStream tsd( &dfile );
1271 
1272  int nplots = pdistrs.size();
1273  int lastp = nplots - 1;
1274  int maxnvl = 0;
1275  line = "";
1276 
1277  for ( int ii = 0; ii < nplots; ii++ )
1278  { // Accumulate long descriptions and build header line
1279  maxnvl = qMax( maxnvl, pdistrs[ ii ].esedcs.size() );
1280  QString pd = pdisIDs[ ii ];
1281  pdlong << pd;
1282  pd = pd.section( ":", 0, 0 ).simplified();
1283  line += "\"" + pd + ".X\",\"" + pd + ".Y\""; // X,Y header entries for contributor
1284 
1285  if ( ii < lastp )
1286  line += ",";
1287  else
1288  line += "\n";
1289  }
1290  tsd << line; // Write header line
1291 
1292  for ( int jj = 0; jj < maxnvl; jj++ )
1293  { // Build and write svalue+boundary data line
1294  line = "";
1295  for ( int ii = 0; ii < nplots; ii++ )
1296  { // Add each X,Y data pair
1297  int nvals = pdistrs[ ii ].esedcs.size();
1298  double* xx = pdistrs[ ii ].esedcs.data();
1299  double* yy = pdistrs[ ii ].efreqs.data();
1300  int kk = qMin( jj, ( nvals - 1 ) );
1301  double sval = xx[ kk ];
1302  double eval = yy[ kk ];
1303 
1304  QString dat = QString().sprintf( "\"%12.5f\",\"%10.5f\"", sval, eval );
1305  dat.replace( " ", "" );
1306  line += dat;
1307 
1308  if ( ii < lastp )
1309  line += ",";
1310  else
1311  line += "\n";
1312  }
1313  tsd << line; // Write data line
1314  }
1315 
1316  dfile.close();
1317 
1318  return;
1319 }
1320 
1321 // Save report documents from files
1322 int US_vHW_Combine::reportDocsFromFiles( QString& runID, QString& fdir,
1323  QStringList& files, US_DB2* db, int& idEdit, QString& trdesc )
1324 {
1325  int ostat = 0;
1326  US_Report freport;
1327  freport.runID = runID;
1328 
1329  for ( int ii = 0; ii < files.size(); ii++ )
1330  {
1331  QString fname = files[ ii ];
1332  int st = freport.saveDocumentFromFile( fdir, fname, db, idEdit, trdesc );
1333 
1334  ostat = ( st == US_Report::REPORT_OK ) ? ostat : st;
1335  }
1336 
1337 //*DEBUG*
1338  if ( dbg_level > 0 )
1339  {
1340  int status = freport.readDB( runID, db );
1341  DbgLv(1) << "DFF:report readDB status" << status << "ID" << freport.ID;
1342  DbgLv(1) << "DFF: report triples size" << freport.triples.size();
1343  for ( int ii = 0; ii < freport.triples.size(); ii++ )
1344  {
1345  int ndoc = freport.triples[ii].docs.size();
1346  DbgLv(1) << "DFF: triple" << ii << "docssize" << ndoc
1347  << "ID" << freport.triples[ii].tripleID
1348  << "triple" << freport.triples[ii].triple;
1349  int jj = ndoc - 1;
1350  if ( ndoc > 0 )
1351  {
1352  DbgLv(1) << "DFF: doc" << 0
1353  << "ID" << freport.triples[ii].docs[0].documentID
1354  << "label" << freport.triples[ii].docs[0].label;
1355  DbgLv(1) << "DFF: doc" << jj
1356  << "ID" << freport.triples[ii].docs[jj].documentID
1357  << "label" << freport.triples[ii].docs[jj].label;
1358  }
1359  }
1360  QString fname = files[0];
1361  QString tripl( "0/Z/9999" );
1362  int ndx = freport.findTriple( tripl );
1363  DbgLv(1) << "DFF:triple" << tripl << "ndx" << ndx;
1364  if ( ndx >= 0 )
1365  {
1366  int ndoc = freport.triples[ndx].docs.size();
1367  DbgLv(1) << "DFF: triple" << ndx << "docs size" << ndoc
1368  << "ID" << freport.triples[ndx].tripleID
1369  << "triple" << freport.triples[ndx].triple;
1370  if ( ndoc > 0 )
1371  {
1372  DbgLv(1) << "DFF: doc" << 0
1373  << "ID" << freport.triples[ndx].docs[0].documentID
1374  << "label" << freport.triples[ndx].docs[0].label;
1375  int jj = ndoc - 1;
1376  DbgLv(1) << "DFF: doc" << jj
1377  << "ID" << freport.triples[ndx].docs[jj].documentID
1378  << "label" << freport.triples[ndx].docs[jj].label;
1379  }
1380  }
1381  }
1382 //*DEBUG*
1383 
1384  return ostat;
1385 }
1386 
1387 // Plot all data in 3D
1389 {
1390  bool eplot = ck_envelope->isChecked();
1391  bool icflag = ck_intconc ->isChecked();
1392  int p_type = eplot ? 0 : ( icflag ? 2 : 1 );
1393  QString wtitle = tr( "Multiwavelength 3-Dimensional vHW Viewer" );
1394  QString ptitle = eplot ? tr( "g(s) Distributions" )
1395  : tr( "G(s) Distributions" );
1396 
1397  QString xatitle = tr( "Sed.C.(*e13)" );
1398  QString yatitle = tr( "Lambda(nm)" );
1399 // QString zatitle = eplot ? tr( "Concen." )
1400 // : tr( "B.Frac." );
1401  QString zatitle = eplot ? tr( "Concen." )
1402  : ( icflag ? tr( "BF*Conc." ) : tr( "Concen." ) );
1403  double xmin = 1e99;
1404  double ymin = 1e99;
1405  double zmin = 1e99;
1406  double xmax = -xmin;
1407  double ymax = -ymin;
1408  double zmax = -zmin;
1409  int ndist = pdistrs.size();
1410  int nrow = ndist;
1411  int ncol = 0;
1412  int nxval = 0;
1413  int nyval = 0;
1414  int minpt = 999999;
1415  int maxpt = 0;
1416 
1417  QList< double > xvals;
1418  QList< double > yvals;
1419  xvals .clear();
1420  yvals .clear();
1421  xyzdat.clear();
1422 
1423  for ( int ii = 0; ii < ndist; ii++ )
1424  {
1425  DistrDesc ddesc = pdistrs[ ii ];
1426  QString wvlen = QString( ddesc.triple ).mid( 2 );
1427  double yval = wvlen.toDouble();
1428  ymin = qMin( ymin, yval );
1429  ymax = qMax( ymax, yval );
1430  int ndispt = ddesc.bfracs.size();
1431  int nenvpt = ddesc.efreqs.size();
1432  double* xx = ddesc.dsedcs.data();
1433  double* zz = ddesc.bfracs.data();
1434  double* xs = ddesc.esedcs.data();
1435  double* zf = ddesc.efreqs.data();
1436 
1437  if ( ! yvals.contains( yval ) )
1438  {
1439  yvals << yval;
1440  nyval++;
1441  }
1442 
1443  int ndpts = eplot ? nenvpt : ndispt;
1444  xx = eplot ? xs : xx;
1445  zz = eplot ? zf : zz;
1446  double zfscl = eplot ? 1.0 : ( ddesc.totconc * 0.01 );
1447  zfscl = icflag ? zfscl : 1.0;
1448  //minpt = qMin( minpt, ndpts );
1449  //maxpt = qMax( maxpt, ndpts );
1450  int knzdp = 0;
1451 
1452  for ( int jj = 0; jj < ndpts; jj++ )
1453  {
1454  double xval = xx[ jj ];
1455  double zval = zz[ jj ] * zfscl;
1456 
1457  if ( zval == 0.0 ) continue;
1458  knzdp++;
1459  xval = qRound( xval * 1.0e4 ) * 1.0e-4;
1460 
1461  if ( ! xvals.contains( xval ) )
1462  {
1463  xvals << xval;
1464  nxval++;
1465  }
1466 
1467  xmin = qMin( xmin, xval );
1468  xmax = qMax( xmax, xval );
1469  zmin = qMin( zmin, zval );
1470  zmax = qMax( zmax, zval );
1471 
1472  xyzdat << QVector3D( xval, yval, zval );
1473  //xyzdat << QVector3D( yval, xval, zval );
1474 DbgLv(0) << "Raw:xyzd: ii jj" << ii << jj << "xyz" << xval << yval << zval;
1475  }
1476 
1477  minpt = qMin( minpt, knzdp );
1478  maxpt = qMax( maxpt, knzdp );
1479  }
1480 
1481  nrow = maxpt;
1482  ncol = nyval;
1483 DbgLv(0) << " nrow ncol nxval nyval" << nrow << ncol << nxval << nyval;
1484 DbgLv(0) << " xmin xmax" << xmin << xmax << "ymin ymax" << ymin << ymax
1485  << "zmin zmax" << zmin << zmax << "xyzd size" << xyzdat.size();
1486 
1487  if ( minpt != maxpt )
1488  { // Sed.Coeff. counts per wavelength vary: create constant count
1489 // nrow = minpt;
1490  xmin = qRound( xmin * 1.0e4 ) * 1.0e-4;
1491  xmax = qRound( xmax * 1.0e4 ) * 1.0e-4;
1492  double xval = xmin;
1493  double yval = yvals[ 0 ];
1494  double xinc = ( xmax - xmin ) / (double)nrow;
1495  QVector< QVector3D > xyzold = xyzdat;
1496  int kidpt = xyzold.count();
1497 // int nrmv = maxpt - minpt;
1498  xyzdat.clear();
1499  xvals .clear();
1500 DbgLv(0) << " xmin xinc" << xmin << xinc << "xyzold count" << kidpt;
1501 
1502  for ( int ii = 0; ii < nrow; ii++, xval += xinc )
1503  xvals << xval;
1504 DbgLv(0) << " xv0 xvn" << xvals[0] << xvals[nrow-1];
1505 
1506  for ( int ii = 0; ii < ncol; ii++ )
1507  {
1508  QVector< double > xvsic; // X values in column
1509  QVector< double > zvsic; // Corresponding Zs in column
1510  yval = yvals[ ii ];
1511 // int krmv = 0;
1512  int krow = 0;
1513 DbgLv(0) << " col" << ii << "yval" << yval;
1514 
1515  for ( int jj = 0; jj < kidpt; jj++ )
1516  {
1517  double yvalo = xyzold[ jj ].y();
1518 
1519  if ( yvalo == yval )
1520  {
1521  double xval = xyzold[ jj ].x();
1522  double zval = xyzold[ jj ].z();
1523 
1524 #if 0
1525  if ( zval == 0.0 && krmv < nrmv )
1526  {
1527  krmv++;
1528  continue;
1529  }
1530 #endif
1531  if ( zval == 0.0 ) continue;
1532 
1533  if ( krow < nrow )
1534  {
1535  xvsic << xval;
1536  zvsic << zval;
1537  krow++;
1538  }
1539  }
1540  }
1541 
1542  int jrow = xvsic.count();
1543  double xlast = qMin( xmax, xvsic[ jrow - 1 ] + xinc );
1544  double zlast = zvsic[ jrow - 1 ];
1545 DbgLv(0) << " jrow" << jrow << "nrow" << nrow
1546  << "xv0,xvn" << xvsic[0] << xvsic[jrow-1];
1547 
1548  for ( int jj = 0; jj < nrow; jj++ )
1549  {
1550  double xval = ( jj < jrow ) ? xvsic[ jj ] : xlast;
1551 // double zval = ( jj < jrow ) ? zvsic[ jj ] : 0.0;
1552  double zval = ( jj < jrow ) ? zvsic[ jj ] : zlast;
1553  xyzdat << QVector3D( xval, yval, zval );
1554  }
1555  }
1556 DbgLv(0) << "xyzd size" << xyzdat.size();
1557  }
1558 
1559  if ( p3d_ctld == NULL )
1560  {
1561  p3d_pltw = NULL;
1562  p3d_ctld = new US_VhwCPlotControl( this, &xyzdat, p_type );
1563 
1564  connect( p3d_ctld, SIGNAL( has_closed() ),
1565  this, SLOT ( control_closed() ) );
1566 
1567  // Position near upper right of the desktop
1568  int cx = qApp->desktop()->width() - p3d_ctld->width() - 40;
1569  int cy = 40;
1570  p3d_ctld->move( cx, cy );
1571  p3d_pltw = p3d_ctld->widget_3dplot();
1572  if ( p3d_pltw != NULL )
1573  {
1574  p3d_pltw->setTitles ( wtitle, ptitle, xatitle, yatitle, zatitle );
1575 DbgLv(0) << "p3db:N: titles" << ptitle << xatitle << yatitle << zatitle;
1576  }
1577  }
1578  else
1579  {
1580  p3d_ctld->setFocus();
1581  p3d_pltw = p3d_ctld->widget_3dplot();
1582 
1583  if ( p3d_pltw != NULL )
1584  {
1585  p3d_pltw->setTitles ( wtitle, ptitle, xatitle, yatitle, zatitle );
1586  p3d_pltw->reloadData( &xyzdat );
1587  p3d_pltw->replot();
1588 DbgLv(0) << "p3db:E: titles" << ptitle << xatitle << yatitle << zatitle;
1589  }
1590 
1591  p3d_ctld->do_3dplot();
1592  }
1593 
1594  p3d_ctld->show();
1595 }
1596 
1597 // Mark plot control window closed
1599 {
1600 DbgLv(1) << "VC: control_closed";
1601  p3d_ctld = NULL;
1602  p3d_pltw = NULL;
1603 }
1604