UltraScan III
us_ga_init.cpp
Go to the documentation of this file.
1 
3 #include <QApplication>
4 
5 #include "us_ga_init.h"
6 #include "us_select_runs.h"
7 #include "us_model_loader.h"
8 #include "us_license_t.h"
9 #include "us_license.h"
10 #include "us_settings.h"
11 #include "us_gui_settings.h"
12 #include "us_math2.h"
13 #include "us_matrix.h"
14 #include "us_constants.h"
15 #include "us_passwd.h"
16 #include "us_report.h"
17 
18 // main program
19 int main( int argc, char* argv[] )
20 {
21  QApplication application( argc, argv );
22 
23  #include "main1.inc"
24 
25  // License is OK. Start up.
26 
28  w.show();
29  return application.exec();
30 }
31 
32 // qSort LessThan method for S_Solute sort
33 bool distro_lessthan( const S_Solute &solu1, const S_Solute &solu2 )
34 { // TRUE iff (s1<s2) || (s1==s2 && k1<k2)
35  return ( solu1.s < solu2.s ) ||
36  ( ( solu1.s == solu2.s ) && ( solu1.k < solu2.k ) );
37 }
38 
39 const double epsilon = 0.0005; // equivalence magnitude ratio radius
40 
41 // US_GA_Initialize class constructor
43 {
44  // set up the GUI
45 
46  setWindowTitle( tr( "Genetic Algorithm Initialization Control Window" ) );
47  setPalette( US_GuiSettings::frameColor() );
48 
49  // primary layouts
50  QHBoxLayout* main = new QHBoxLayout( this );
51  QVBoxLayout* left = new QVBoxLayout();
52  QVBoxLayout* rght = new QVBoxLayout();
53  QGridLayout* spec = new QGridLayout();
54  main->setSpacing ( 2 );
55  main->setContentsMargins( 2, 2, 2, 2 );
56  left->setSpacing ( 0 );
57  left->setContentsMargins( 0, 1, 0, 1 );
58  spec->setSpacing ( 1 );
59  spec->setContentsMargins( 0, 0, 0, 0 );
60  rght->setSpacing ( 0 );
61  rght->setContentsMargins( 0, 1, 0, 1 );
62 
64 
65  // Insure working etc is populated with color maps
66  clean_etc_dir( true );
67 
68  // series of rows: most of them label on left, counter/box on right
69  lb_info1 = us_banner( tr( "Genetic Algorithm Controls" ) );
70 
71  lb_nisols = us_label( tr( "Number of Initial Solutes:" ) );
72  lb_nisols->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
73 
74  ct_nisols = us_counter( 3, 0.0, 1000.0, 0.0 );
75  ct_nisols->setStep( 1 );
76  ct_nisols->setEnabled( true );
77  connect( ct_nisols, SIGNAL( valueChanged( double ) ),
78  this, SLOT( update_nisols( double ) ) );
79 
80  lb_wxbuck = us_label( tr( "Width of s Bucket:" ) );
81  lb_wxbuck->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
82 
83  ct_wxbuck = us_counter( 3, 0.0, 10.0, 0.0 );
84  ct_wxbuck->setStep( 1 );
85  connect( ct_wxbuck, SIGNAL( valueChanged( double ) ),
86  this, SLOT( update_wxbuck( double ) ) );
87 
88  lb_hybuck = us_label( tr( "Height of f/f0 Bucket:" ) );
89  lb_hybuck->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
90 
91  ct_hybuck = us_counter( 3, 0.0, 1.0, 0.0 );
92  ct_hybuck->setStep( 1 );
93  connect( ct_hybuck, SIGNAL( valueChanged( double ) ),
94  this, SLOT( update_hybuck( double ) ) );
95 
96  lb_info2 = us_banner( tr( "Pseudo-3D Controls" ) );
97 
98  lb_resolu = us_label( tr( "Pseudo-3D Resolution:" ) );
99  lb_resolu->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
100 
101  ct_resolu = us_counter( 3, 0.0, 100.0, 90.0 );
102  ct_resolu->setStep( 1 );
103  connect( ct_resolu, SIGNAL( valueChanged( double ) ),
104  this, SLOT( update_resolu( double ) ) );
105 
106  lb_xreso = us_label( tr( "X Resolution:" ) );
107  lb_xreso->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
108 
109  ct_xreso = us_counter( 3, 10.0, 1000.0, 0.0 );
110  ct_xreso->setStep( 1 );
111  connect( ct_xreso, SIGNAL( valueChanged( double ) ),
112  this, SLOT( update_xreso( double ) ) );
113 
114  lb_yreso = us_label( tr( "Y Resolution:" ) );
115  lb_yreso->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
116 
117  ct_yreso = us_counter( 3, 10.0, 1000.0, 0.0 );
118  ct_yreso->setStep( 1 );
119  connect( ct_yreso, SIGNAL( valueChanged( double ) ),
120  this, SLOT( update_yreso( double ) ) );
121 
122  lb_zfloor = us_label( tr( "Z Floor Percent:" ) );
123  lb_zfloor->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
124 
125  ct_zfloor = us_counter( 3, 0.0, 50.0, 1.0 );
126  ct_zfloor->setStep( 1 );
127  connect( ct_zfloor, SIGNAL( valueChanged( double ) ),
128  this, SLOT( update_zfloor( double ) ) );
129 
130  lb_autlim = us_label( tr( "Automatic Plot Limits" ) );
131  lb_autlim->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
132 
133  us_checkbox( tr( "(unselect to override) " ), ck_autlim, true );
134  connect( ck_autlim, SIGNAL( clicked() ),
135  this, SLOT( select_autolim() ) );
136 
137  lb_plxmin = us_label( tr( "Plot Limit s Min:" ) );
138  lb_plxmin->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
139 
140  ct_plxmin = us_counter( 3, -10000.0, 10000.0, 0.0 );
141  ct_plxmin->setStep( 1 );
142  connect( ct_plxmin, SIGNAL( valueChanged( double ) ),
143  this, SLOT( update_plxmin( double ) ) );
144 
145  lb_plxmax = us_label( tr( "Plot Limit s Max:" ) );
146  ct_plxmax = us_counter( 3, 0.0, 10000.0, 0.0 );
147  ct_plxmax->setStep( 1 );
148  connect( ct_plxmax, SIGNAL( valueChanged( double ) ),
149  this, SLOT( update_plxmax( double ) ) );
150 
151  lb_plymin = us_label( tr( "Plot Limit f/f0 Min:" ) );
152  lb_plymin->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
153 
154  ct_plymin = us_counter( 3, 0.5, 50.0, 0.0 );
155  ct_plymin->setStep( 1 );
156  connect( ct_plymin, SIGNAL( valueChanged( double ) ),
157  this, SLOT( update_plymin( double ) ) );
158 
159  lb_plymax = us_label( tr( "Plot Limit f/f0 Max:" ) );
160  lb_plymax->setAlignment( Qt::AlignVCenter | Qt::AlignLeft );
161 
162  ct_plymax = us_counter( 3, 1.0, 50.0, 1.0 );
163  ct_plymax->setStep( 1 );
164  ct_plymax->setValue( 1.34567e+01 );
165  connect( ct_plymax, SIGNAL( valueChanged( double ) ),
166  this, SLOT( update_plymax( double ) ) );
167 
169  lw_sbin_data->installEventFilter( this );
170  connect( lw_sbin_data, SIGNAL( clicked( const QModelIndex& ) ),
171  this, SLOT( sclick_sbdata( const QModelIndex& ) ) );
172  connect( lw_sbin_data, SIGNAL( doubleClicked( const QModelIndex& ) ),
173  this, SLOT( dclick_sbdata( const QModelIndex& ) ) );
174  connect( lw_sbin_data, SIGNAL( currentRowChanged( int ) ),
175  this, SLOT( newrow_sbdata( int ) ) );
176 
177  attr_x = 0;
178  attr_y = 1;
179  attr_z = 3;
180  QLabel* lb_x_axis = us_label( tr( "Plot X:" ) );
181  QLabel* lb_y_axis = us_label( tr( "Plot Y:" ) );
182  bg_x_axis = new QButtonGroup( this );
183  bg_y_axis = new QButtonGroup( this );
184  QGridLayout* gl_x_s = us_radiobutton( tr( "s" ), rb_x_s, true );
185  QGridLayout* gl_x_ff0 = us_radiobutton( tr( "ff0" ), rb_x_ff0, false );
186  QGridLayout* gl_x_mw = us_radiobutton( tr( "mw" ), rb_x_mw, false );
187  QGridLayout* gl_x_vbar = us_radiobutton( tr( "vbar" ), rb_x_vbar, false );
188  QGridLayout* gl_x_D = us_radiobutton( tr( "D" ), rb_x_D, false );
189  QGridLayout* gl_x_f = us_radiobutton( tr( "f" ), rb_x_f, false );
190  QGridLayout* gl_y_s = us_radiobutton( tr( "s" ), rb_y_s, false );
191  QGridLayout* gl_y_ff0 = us_radiobutton( tr( "ff0" ), rb_y_ff0, true );
192  QGridLayout* gl_y_mw = us_radiobutton( tr( "mw" ), rb_y_mw, false );
193  QGridLayout* gl_y_vbar = us_radiobutton( tr( "vbar" ), rb_y_vbar, false );
194  QGridLayout* gl_y_D = us_radiobutton( tr( "D" ), rb_y_D, false );
195  QGridLayout* gl_y_f = us_radiobutton( tr( "f" ), rb_y_f, false );
196  bg_x_axis->addButton( rb_x_s, ATTR_S );
197  bg_x_axis->addButton( rb_x_ff0, ATTR_K );
198  bg_x_axis->addButton( rb_x_mw, ATTR_W );
199  bg_x_axis->addButton( rb_x_vbar, ATTR_V );
200  bg_x_axis->addButton( rb_x_D, ATTR_D );
201  bg_x_axis->addButton( rb_x_f, ATTR_F );
202  bg_y_axis->addButton( rb_y_s, ATTR_S );
203  bg_y_axis->addButton( rb_y_ff0, ATTR_K );
204  bg_y_axis->addButton( rb_y_mw, ATTR_W );
205  bg_y_axis->addButton( rb_y_vbar, ATTR_V );
206  bg_y_axis->addButton( rb_y_D, ATTR_D );
207  bg_y_axis->addButton( rb_y_f, ATTR_F );
208  rb_x_s ->setChecked( true );
209  rb_y_s ->setEnabled( false );
210  rb_y_ff0 ->setChecked( true );
211  rb_x_ff0 ->setEnabled( false );
212  rb_x_s ->setToolTip( tr( "Set X axis to Sedimentation Coefficient" ) );
213  rb_x_ff0 ->setToolTip( tr( "Set X axis to Frictional Ratio" ) );
214  rb_x_mw ->setToolTip( tr( "Set X axis to Molecular Weight" ) );
215  rb_x_vbar->setToolTip( tr( "Set X axis to Partial Specific Volume" ) );
216  rb_x_D ->setToolTip( tr( "Set X axis to Diffusion Coefficient" ) );
217  rb_x_f ->setToolTip( tr( "Set X axis to Frictional Coefficient" ) );
218  rb_y_s ->setToolTip( tr( "Set Y axis to Sedimentation Coefficient" ) );
219  rb_y_ff0 ->setToolTip( tr( "Set Y axis to Frictional Ratio" ) );
220  rb_y_mw ->setToolTip( tr( "Set Y axis to Molecular Weight" ) );
221  rb_y_vbar->setToolTip( tr( "Set Y axis to Partial Specific Volume" ) );
222  rb_y_D ->setToolTip( tr( "Set Y axis to Diffusion Coefficient" ) );
223  rb_y_f ->setToolTip( tr( "Set Y axis to Frictional Coefficient" ) );
224  connect( bg_x_axis, SIGNAL( buttonReleased( int ) ),
225  this, SLOT( select_x_axis ( int ) ) );
226  connect( bg_y_axis, SIGNAL( buttonReleased( int ) ),
227  this, SLOT( select_y_axis ( int ) ) );
228 
231  connect( dkdb_cntrls, SIGNAL( changed( bool ) ),
232  this, SLOT( update_disk_db( bool ) ) );
233 
234  pb_prefilt = us_pushbutton( tr( "Select PreFilter" ) );
235  pb_prefilt->setEnabled( true );
236  connect( pb_prefilt, SIGNAL( clicked() ),
237  this, SLOT( select_prefilt() ) );
238 
239  le_prefilt = us_lineedit ( "", -1, true );
240 
241  pb_lddistr = us_pushbutton( tr( "Load Distribution" ) );
242  pb_lddistr->setEnabled( true );
243  connect( pb_lddistr, SIGNAL( clicked() ),
244  this, SLOT( load_distro() ) );
245 
246  us_checkbox( tr( "1-Dimensional Plot" ), ck_1dplot, false );
247  connect( ck_1dplot, SIGNAL( clicked() ),
248  this, SLOT( select_plot1d() ) );
249 
250  pb_ldcolor = us_pushbutton( tr( "Load Color File" ) );
251  pb_ldcolor->setEnabled( true );
252  connect( pb_ldcolor, SIGNAL( clicked() ),
253  this, SLOT( load_color() ) );
254 
255  us_checkbox( tr( "2-Dimensional Plot" ), ck_2dplot, false );
256  connect( ck_2dplot, SIGNAL( clicked() ),
257  this, SLOT( select_plot2d() ) );
258 
259  pb_refresh = us_pushbutton( tr( "Refresh Plot" ) );
260  pb_refresh->setEnabled( false );
261  connect( pb_refresh, SIGNAL( clicked() ),
262  this, SLOT( replot_data() ) );
263 
264  us_checkbox( tr( "Pseudo 3-D Plot" ), ck_3dplot, true );
265  connect( ck_3dplot, SIGNAL( clicked() ),
266  this, SLOT( select_plot3d() ) );
267 
268  pb_mandrsb = us_pushbutton( tr( "Manually Draw Bins" ) );
269  pb_mandrsb->setEnabled( false );
270  connect( pb_mandrsb, SIGNAL( clicked() ),
271  this, SLOT( manDrawSb() ) );
272 
273  pb_ckovrlp = us_pushbutton( tr( "Check for Bin Overlaps / Sort" ) );
274  pb_ckovrlp->setEnabled( false );
275  connect( pb_ckovrlp, SIGNAL( clicked() ),
276  this, SLOT( checkOverlaps() ) );
277 
278  pb_autassb = us_pushbutton( tr( "Autoassign Solute Bins" ) );
279  pb_autassb->setEnabled( false );
280  connect( pb_autassb, SIGNAL( clicked() ),
281  this, SLOT( autoAssignSb() ) );
282 
283  pb_resetsb = us_pushbutton( tr( "Reset Solute Bins" ) );
284  pb_resetsb->setEnabled( false );
285  connect( pb_resetsb, SIGNAL( clicked() ),
286  this, SLOT( resetSb() ) );
287 
288  pb_reset = us_pushbutton( tr( "Reset" ) );
289  pb_reset->setEnabled( false );
290  connect( pb_reset, SIGNAL( clicked() ),
291  this, SLOT( reset() ) );
292 
293  pb_view = us_pushbutton( tr( "View Statistics" ) );
294  pb_view ->setEnabled( false );
295  connect( pb_view, SIGNAL( clicked() ),
296  this, SLOT( view() ) );
297 
298  pb_save = us_pushbutton( tr( "Save" ) );
299  pb_save->setEnabled( false );
300  connect( pb_save, SIGNAL( clicked() ),
301  this, SLOT( save() ) );
302 
303  pb_help = us_pushbutton( tr( "Help" ) );
304  pb_help->setEnabled( true );
305  connect( pb_help, SIGNAL( clicked() ),
306  this, SLOT( help() ) );
307 
308  pb_close = us_pushbutton( tr( "Close" ) );
309  pb_close->setEnabled( true );
310  connect( pb_close, SIGNAL( clicked() ),
311  this, SLOT( close() ) );
312 
313  te_status = us_textedit( );
314  te_status->setTextBackgroundColor( Qt::white );
315  te_status->setTextColor( Qt::blue );
316  dfilname = "(NONE)";
317  stcmline = tr( "Color Map: the default w-cyan-magenta-red-black" );
318  stdiline = tr( "The distribution was loaded from the file:" );
319  stdfline = " " + dfilname;
320  stfxline = tr( "Components fixed attribute is \"vbar\"." );
321  stnpline = tr( "The number of distribution points is 0." );
322  te_status->setText( stcmline + "\n" + stdiline + "\n"
323  + stdfline + "\n" + stfxline + "\n" + stnpline );
324 
325  int s_row = 0;
326  spec->addWidget( lb_info1, s_row++, 0, 1, 8 );
327  spec->addWidget( lb_nisols, s_row, 0, 1, 4 );
328  spec->addWidget( ct_nisols, s_row++, 4, 1, 4 );
329  spec->addWidget( lb_wxbuck, s_row, 0, 1, 4 );
330  spec->addWidget( ct_wxbuck, s_row++, 4, 1, 4 );
331  spec->addWidget( lb_hybuck, s_row, 0, 1, 4 );
332  spec->addWidget( ct_hybuck, s_row++, 4, 1, 4 );
333  spec->addWidget( lb_info2, s_row++, 0, 1, 8 );
334  spec->addWidget( lb_resolu, s_row, 0, 1, 4 );
335  spec->addWidget( ct_resolu, s_row++, 4, 1, 4 );
336  spec->addWidget( lb_xreso, s_row, 0, 1, 4 );
337  spec->addWidget( ct_xreso, s_row++, 4, 1, 4 );
338  spec->addWidget( lb_yreso, s_row, 0, 1, 4 );
339  spec->addWidget( ct_yreso, s_row++, 4, 1, 4 );
340  spec->addWidget( lb_zfloor, s_row, 0, 1, 4 );
341  spec->addWidget( ct_zfloor, s_row++, 4, 1, 4 );
342  spec->addWidget( lb_autlim, s_row, 0, 1, 4 );
343  spec->addWidget( ck_autlim, s_row++, 4, 1, 4 );
344  spec->addWidget( lb_plxmin, s_row, 0, 1, 4 );
345  spec->addWidget( ct_plxmin, s_row++, 4, 1, 4 );
346  spec->addWidget( lb_plxmax, s_row, 0, 1, 4 );
347  spec->addWidget( ct_plxmax, s_row++, 4, 1, 4 );
348  spec->addWidget( lb_plymin, s_row, 0, 1, 4 );
349  spec->addWidget( ct_plymin, s_row++, 4, 1, 4 );
350  spec->addWidget( lb_plymax, s_row, 0, 1, 4 );
351  spec->addWidget( ct_plymax, s_row++, 4, 1, 4 );
352  spec->addWidget( lw_sbin_data, s_row++, 0, 1, 8 );
353  spec->addWidget( lb_x_axis, s_row, 0, 1, 2 );
354  spec->addLayout( gl_x_s, s_row, 2, 1, 1 );
355  spec->addLayout( gl_x_ff0, s_row, 3, 1, 1 );
356  spec->addLayout( gl_x_mw, s_row, 4, 1, 1 );
357  spec->addLayout( gl_x_vbar, s_row, 5, 1, 1 );
358  spec->addLayout( gl_x_D, s_row, 6, 1, 1 );
359  spec->addLayout( gl_x_f, s_row++, 7, 1, 1 );
360  spec->addWidget( lb_y_axis, s_row, 0, 1, 2 );
361  spec->addLayout( gl_y_s, s_row, 2, 1, 1 );
362  spec->addLayout( gl_y_ff0, s_row, 3, 1, 1 );
363  spec->addLayout( gl_y_mw, s_row, 4, 1, 1 );
364  spec->addLayout( gl_y_vbar, s_row, 5, 1, 1 );
365  spec->addLayout( gl_y_D, s_row, 6, 1, 1 );
366  spec->addLayout( gl_y_f, s_row++, 7, 1, 1 );
367  spec->addLayout( dkdb_cntrls, s_row++, 0, 1, 8 );
368  spec->addWidget( pb_prefilt, s_row, 0, 1, 4 );
369  spec->addWidget( le_prefilt, s_row++, 4, 1, 4 );
370  spec->addWidget( pb_lddistr, s_row, 0, 1, 4 );
371  spec->addWidget( ck_1dplot, s_row++, 4, 1, 4 );
372  spec->addWidget( pb_ldcolor, s_row, 0, 1, 4 );
373  spec->addWidget( ck_2dplot, s_row++, 4, 1, 4 );
374  spec->addWidget( pb_refresh, s_row, 0, 1, 4 );
375  spec->addWidget( ck_3dplot, s_row++, 4, 1, 4 );
376  spec->addWidget( pb_mandrsb, s_row, 0, 1, 4 );
377  spec->addWidget( pb_ckovrlp, s_row++, 4, 1, 4 );
378  spec->addWidget( pb_autassb, s_row, 0, 1, 4 );
379  spec->addWidget( pb_resetsb, s_row++, 4, 1, 4 );
380  spec->addWidget( pb_reset, s_row, 0, 1, 4 );
381  spec->addWidget( pb_save, s_row++, 4, 1, 4 );
382  spec->addWidget( pb_view, s_row, 0, 1, 4 );
383  spec->addWidget( pb_help, s_row, 4, 1, 2 );
384  spec->addWidget( pb_close, s_row++, 6, 1, 2 );
385  spec->addWidget( te_status, s_row++, 0, 6, 8 );
386 
387  // set up plot component window on right side
388  xa_title = tr( "Sedimentation Coefficient corrected for water at 20" )
389  + DEGC;
390  ya_title = tr( "Frictional Ratio f/f0" );
391 
392  QBoxLayout* plot = new US_Plot( data_plot,
393  tr( "Distribution Data" ), xa_title, ya_title );
394  rght->addLayout( plot );
395  QBoxLayout* txed = new QHBoxLayout;
397  te_pctl_help->setText( tr(
398  "Please load a sedimentation coefficient or molecular weight"
399  " distribution to initialize the genetic algorithm s-value or mw-value"
400  " range. The distribution should have a good resolution over the"
401  " sedimentation or weight coefficients. This distribution will be "
402  " used to initialize all experiments used in the run, so the"
403  " distribution taken from the experiment with the highest speed is"
404  " probably the most appropriate distribution. You can use a distribution"
405  " from the van Holde - Weischet method, the C(s) method, or 2-D Spectrum"
406  " Analysis. You may also load a Monte Carlo distribution." ) );
407  us_setReadOnly( te_pctl_help, true );
408  txed->addWidget( te_pctl_help );
409  rght->addLayout( txed );
410  rght->setStretchFactor( plot, 4 );
411  rght->setStretchFactor( txed, 1 );
412 
413  data_plot->setAutoDelete( true );
414  data_plot->setMinimumSize( 600, 600 );
415 
416  data_plot->enableAxis( QwtPlot::xBottom, true );
417  data_plot->enableAxis( QwtPlot::yLeft, true );
418  data_plot->enableAxis( QwtPlot::yRight, true );
419  data_plot->setAxisScale( QwtPlot::xBottom, 1.0, 40.0 );
420  data_plot->setAxisScale( QwtPlot::yLeft, 1.0, 4.0 );
421 
422  data_plot->setCanvasBackground( Qt::darkBlue );
423 
424  // put layouts together for overall layout
425  left->addLayout( spec );
426 
427  main->addLayout( left );
428  main->addLayout( rght );
429  main->setStretchFactor( left, 3 );
430  main->setStretchFactor( spec, 3 );
431  main->setStretchFactor( rght, 5 );
432 
433  // set up variables and initial state of GUI
434  soludata = new US_SoluteData();
435  sdistro = &xy_distro;
436  plot_dim = 3; // default plot dimension
437  attr_x = 0; // default X type: s
438  attr_y = 1; // default Y type: f/f0
439  attr_z = 3; // default Z (fixed) type: vbar
440  rbtn_click = false; // default right-button clicked
441  mfilter = ""; // default model list filter
442  runsel = true; // default prefilter type
443  latest = true; // default edit prefilter type
444  is_saved = false; // files have been saved
445  pfilts.clear(); // default prefilter edits list
446 
447  reset();
448 }
449 
450 // reset the GUI
452 {
453  data_plot->detachItems( );
454  data_plot->replot();
455  pick = new US_PlotPicker( data_plot );
456 
457  lw_sbin_data->clear();
459  sxset = 0;
460 
461  minmax = false;
462  zoom = false;
463  ck_1dplot->setChecked( plot_dim == 1 );
464  ck_2dplot->setChecked( plot_dim == 2 );
465  ck_3dplot->setChecked( plot_dim == 3 );
466 
467  nisols = 0;
468  nibuks = 0;
469  wxbuck = 0.0;
470  hybuck = 0.0;
471  ct_nisols->setValue( (double)nisols );
472  ct_wxbuck->setRange( 0, 200, 0.1 );
473  ct_hybuck->setRange( 0, 50, 0.01 );
474  ct_wxbuck->setValue( wxbuck );
475  ct_hybuck->setValue( hybuck );
476 
477  resolu = 90.0;
478  ct_resolu->setRange( 1, 100, 1 );
479  ct_resolu->setValue( resolu );
480 
481  xreso = 300.0;
482  yreso = 300.0;
483  ct_xreso->setRange( 10.0, 1000.0, 1.0 );
484  ct_xreso->setValue( (double)xreso );
485  ct_yreso->setRange( 10, 1000, 1 );
486  ct_yreso->setValue( (double)yreso );
487 
488  zfloor = 5.0;
489  ct_zfloor->setRange( 0, 50, 1 );
490  ct_zfloor->setValue( (double)zfloor );
491 
492  auto_lim = true;
493  ck_autlim->setChecked( auto_lim );
494 
495  plymin = 1.0;
496  plymax = 4.0;
497  ct_plymin->setRange( 0.5, 50, 0.01 );
498  ct_plymin->setValue( plymin );
499  ct_plymin->setEnabled( false );
500  ct_plymax->setRange( 1.0, 50, 0.01 );
501  ct_plymax->setValue( plymax );
502  ct_plymax->setEnabled( false );
503 
504  plxmin = 1.0;
505  plxmax = 10.0;
506  ct_plxmin->setRange( -10.0, 10000.0, 0.01 );
507  ct_plxmin->setValue( plxmin );
508  ct_plxmin->setEnabled( false );
509  ct_plxmax->setRange( 0.0, 10000.0, 0.01 );
510  ct_plxmax->setValue( plxmax );
511  ct_plxmax->setEnabled( false );
512 
513  // default to white-cyan-magenta-red-black color map
514  colormap = new QwtLinearColorMap( Qt::white, Qt::black );
515  colormap->addColorStop( 0.10, Qt::cyan );
516  colormap->addColorStop( 0.50, Qt::magenta );
517  colormap->addColorStop( 0.80, Qt::red );
518  cmapname = tr( "Default Color Map: w-cyan-magenta-red-black" );
519 
520  monte_carlo = false;
521  is_saved = false;
522  pb_reset ->setEnabled( false );
523 }
524 
525 // save the GA data
527 {
528  // Sort the buckets in increasing-s order
529  int hlx = lw_sbin_data->currentRow();
531 
532  // Reset the buckets plot and list
533  resetPlotAndList( hlx );
534 
535  // Test for overlaps
536  int novlps = soludata->countOverlaps();
537 DbgLv(1) << "SAVE novlps" << novlps;
538 
539  if ( novlps > 0 )
540  {
541  QString msg = ( novlps == 1 ) ?
542  tr( "There is one case of overlap between bins.\n" ) :
543  tr( "%1 pairs of bins overlap one another.\n" ).arg( novlps );
544  QMessageBox::warning( this,
545  tr( "Bin Overlaps" ),
546  msg + tr( "You must correct this condition so that\n"
547  "no bins overlap, before you can save GA data." ) );
548  return;
549  }
550 
551  if ( attr_x != ATTR_V && attr_y != ATTR_V && attr_z != ATTR_V )
552  { // None of X,Y,fixed is vbar: there can be no output file
553  QMessageBox::information( this,
554  tr( "No Files Output" ),
555  tr( "No files will be saved, since neither X,Y nor fixed attribute"
556  " is vbar.\n\n"
557  "To output a gadistro file, insure that one of X,Y,fixed"
558  " is vbar." ) );
559  return;
560  }
561 
562  QString runid = run_name.section( ".", 0, -2 );
563  if ( runid.startsWith( "Global-" ) )
564  runid = runid.mid( 7 );
565  QString trpid = run_name.section( ".", -1, -1 );
566  QString fdir = US_Settings::resultDir() + "/" + runid;
567  QString fndat = "gainit." + trpid + ".gadistro.dat";
568  QString fnsta = "gainit." + trpid + ".sol_integ.stats";
569  QString fname = fdir + "/" + fndat;
570  QString fdir2 = US_Settings::reportDir() + "/" + runid;
571  QString fnst2 = method + "." + trpid + ".statistics.rpt";
572  QString fnam2 = fdir2 + "/" + fnst2;
573 
574  QDir dirp( US_Settings::resultDir() );
575 
576  if ( ! dirp.exists( fdir ) )
577  dirp.mkpath( fdir );
578 
579  if ( ! dirp.exists( fdir2 ) )
580  dirp.mkpath( fdir2 );
581 
582 DbgLv(1) << "SAVE ax,y,z" << attr_x << attr_y << attr_z;
583  double fixval = 0.0;
584  fixval = ( attr_z == ATTR_S ) ? sk_distro[ 0 ].s : fixval;
585  fixval = ( attr_z == ATTR_K ) ? sk_distro[ 0 ].k : fixval;
586  fixval = ( attr_z == ATTR_W ) ? sk_distro[ 0 ].w : fixval;
587  fixval = ( attr_z == ATTR_D ) ? sk_distro[ 0 ].d : fixval;
588  fixval = ( attr_z == ATTR_F ) ? sk_distro[ 0 ].f : fixval;
589 
590  soludata->saveGAdata( fname, attr_x, attr_y, attr_z, fixval );
591 
592  // Report on files saved
593  QString msg = tr( "Saved:\n " ) + fndat + "\n";
594 
595  if ( manbuks )
596  { // if manual buckets, build up and analyze data, then report
597 
598 DbgLv(1) << "SAVE call buildMC";
599  soludata->buildDataMC(); // build it
600 
601  fname = fdir + "/" + fnsta;
602 
603 DbgLv(1) << "SAVE call reportMC";
604  soludata->reportDataMC( fname, mc_iters ); // report it
605  is_saved = true;
606 
607  // Copy the statistics file to the report directory
608  QFile( fnam2 ).remove();
609  QFile( fname ).copy( fnam2 );
610  pb_view ->setEnabled( true );
611 
612  msg += " " + fnsta + "\n";
613  msg += tr( "in directory:\n " ) + fdir + tr( "\n\nand\n" );
614  msg += " " + fnst2 + "\n";
615  msg += tr( "in directory:\n " ) + fdir2;
616 
617  if ( dkdb_cntrls->db() )
618  { // Write statistics report to database
619  US_Passwd pw;
620  US_DB2 db( pw.getPasswd() );
621  US_DB2* dbP = &db;
622  QStringList query;
623 
624  query << "get_editID" << editGUID;
625  db.query( query );
626  db.next();
627  int idEdit = db.value( 0 ).toString().toInt();
628  US_Report freport;
629  freport.runID = runid;
630 
631  int status =
632  freport.saveDocumentFromFile( fdir2, fnst2, dbP, idEdit );
633 
634  if ( status == US_Report::REPORT_OK )
635  msg += tr( "\n\nThe report file was also saved to the database" );
636  else
637  msg += tr( "\n\n*ERROR* attempting save of report to database." );
638  }
639  }
640 
641  else
642  {
643 DbgLv(1) << "SAVE fnst2" << fnst2;
644  msg += tr( "in directory:\n " ) + fdir;
645  }
646 
647  QMessageBox::information( this, tr( "Distro/Stats File Save" ), msg );
648 }
649 
650 // Manually draw solute bins
652 {
653  QColor cblack( Qt::black );
654  QColor cwhite( Qt::white );
655 
656  // create a new plot picker to draw rectangles around solute points
657  delete pick;
658  pick = new US_PlotPicker( data_plot );
659 
660  // make sure rubber band and tracker show up against background
661  QColor bg = data_plot->canvasBackground();
662  int csum = bg.red() + bg.green() + bg.blue();
663  pickpen = new QPen( ( csum > 600 ) ? cblack : cwhite );
664 
665  pick->setRubberBandPen( *pickpen );
666  pick->setTrackerPen( *pickpen );
667  pick->setRubberBand( QwtPicker::RectRubberBand );
668  pick->setSelectionFlags( QwtPicker::RectSelection
669  | QwtPicker::DragSelection );
670 
671  // set up to capture position and dimensions of solute bin
672  connect( pick, SIGNAL( mouseDown( const QwtDoublePoint& ) ),
673  this, SLOT( getMouseDown( const QwtDoublePoint& ) ) );
674  connect( pick, SIGNAL( mouseUp( const QwtDoublePoint& ) ),
675  this, SLOT( getMouseUp( const QwtDoublePoint& ) ) );
676 
677  pb_ckovrlp->setEnabled( false );
678 
679  wxbuck = ( plxmax - plxmin ) / 20.0;
680  hybuck = ( plymax - plymin ) / 20.0;
681  ct_wxbuck->disconnect( );
682  ct_hybuck->disconnect( );
683  int rpwr = qRound( log10( wxbuck ) );
684  double rmax = pow( 10.0, rpwr + 3 );
685  double rinc = pow( 10.0, rpwr - 3 );
686  wxbuck = qRound( wxbuck / rinc ) * rinc;
687  ct_wxbuck->setRange( 0.0, rmax, rinc );
688  ct_wxbuck->setValue( wxbuck );
689  rpwr = qRound( log10( hybuck ) );
690  rmax = pow( 10.0, rpwr + 3 );
691  rinc = pow( 10.0, rpwr - 3 );
692  hybuck = qRound( hybuck / rinc ) * rinc;
693  ct_hybuck->setValue( hybuck );
694  connect( ct_wxbuck, SIGNAL( valueChanged( double ) ),
695  this, SLOT( update_wxbuck( double ) ) );
696  connect( ct_hybuck, SIGNAL( valueChanged( double ) ),
697  this, SLOT( update_hybuck( double ) ) );
698 
699  manbuks = true;
700 }
701 
702 // Check for bin overlaps
704 {
705  int novlps = soludata->countOverlaps();
706 
707  if ( novlps == 0 )
708  {
709  QMessageBox::information( this,
710  tr( "No Bins Overlap" ),
711  tr( "No bin overlaps were found, so you"
712  " may proceed to saving this GA data"
713  " or viewing statistics."
714  "\n\n*NOTE*: Bins will now be re-sorted." ) );
715  pb_save->setEnabled( attr_x == ATTR_V ||
716  attr_y == ATTR_V ||
717  attr_z == ATTR_V );
718  pb_view->setEnabled( true );
719  }
720 
721  else
722  {
723  QString msg = ( novlps == 1 ) ?
724  tr( "There is one case of overlap between bins.\n" ) :
725  tr( "%1 pairs of bins overlap one another.\n" ).arg( novlps );
726  QMessageBox::warning( this,
727  tr( "Bin Overlaps" ),
728  msg + tr( "You must correct this condition so that no\n"
729  "bins overlap, before you can save GA data." ) );
730  pb_save->setEnabled( false );
731  pb_view->setEnabled( false );
732  }
733 
734  // Sort buckets, then reset the buckets plot and list
736  int hlx = lw_sbin_data->currentRow();
737  resetPlotAndList( hlx );
738 }
739 
740 // Auto assign solute bins
742 {
743  nisols = ( nisols == 0 ) ? sdistro->size() : nisols;
744  pc1 = NULL;
745  lw_sbin_data->clear();
747  erase_buckets( true );
748 
750 
751  for ( int jj = 0; jj < nibuks; jj++ )
752  { // draw the auto-assigned buckets and add lines to list widget
753  QRectF rect = soludata->bucketRect( jj );
754  pc1 = drawBucketRect( jj, rect );
755 
756  lw_sbin_data->addItem( soludata->bucketLine( jj ) );
757  }
758 
759  data_plot->replot();
760  pb_resetsb->setEnabled( true );
761  // X,Y or fixed must be vbar for Save to be allowed
762  pb_save ->setEnabled( ( attr_x == ATTR_V ) ||
763  ( attr_y == ATTR_V ) ||
764  ( attr_z == ATTR_V ) );
765  pb_ckovrlp->setEnabled( true );
766  pb_view ->setEnabled( false );
767 
768  manbuks = false;
769 }
770 
771 // Reset solute bins
773 {
774  ct_nisols->setValue( 0.0 );
775  lw_sbin_data->clear(); // clear solute bucket data
777  sxset = 0;
778  is_saved = false;
779 
780  erase_buckets( true ); // erase bucket rectangles from plot and delete
781 
782  nibuks = 0;
783  pb_save ->setEnabled( false );
784  pb_view ->setEnabled( false );
785  pb_ckovrlp->setEnabled( false );
786 
787  data_plot->replot();
788 }
789 
790 // (re)plot data
792 {
793  if ( sdistro->isEmpty() || sdistro->size() == 0 )
794  return;
795 
796  resetSb();
797 
798  sdistro = &xy_distro;
799 
800  if ( plot_dim == 1 )
801  {
802  plot_1dim();
803  }
804  else if ( plot_dim == 2 )
805  {
806  plot_2dim();
807  }
808  else
809  {
810  plot_3dim();
811  }
812 
813  setBucketPens();
814 }
815 
816 // plot data 1-D
818 {
819  data_plot->detachItems();
820 
821  data_plot->setCanvasBackground( Qt::black );
822  pick->setTrackerPen( QColor( Qt::white ) );
823 
824  int dsize = sdistro->size();
825  QVector< double > xvec( dsize );
826  QVector< double > yvec( dsize );
827  double* x = xvec.data();
828  double* y = yvec.data();
829  double sval = sdistro->at( 0 ).s;
830  double smin = sval;
831  double smax = sval;
832  double cval = sdistro->at( 0 ).c;
833  double cmin = cval;
834  double cmax = cval;
835  int nn = 1;
836  x[ 0 ] = sval;
837  y[ 0 ] = cval;
838 
839  for ( int jj = 1; jj < dsize; jj++ )
840  {
841  double svpr = sval;
842  double cvpr = cval;
843  sval = sdistro->at( jj ).s;
844  cval = sdistro->at( jj ).c;
845 
846  if ( equivalent( sval, svpr, epsilon ) )
847  { // effectively equal s values: sum c values
848  cval += cvpr;
849  x[ nn - 1 ] = ( svpr + sval ) * 0.5;
850  y[ nn - 1 ] = cval;
851  }
852 
853  else
854  { // new s value: save c value and bump count
855  x[ nn ] = sval;
856  y[ nn++ ] = cval;
857  }
858 
859  smin = ( smin < sval ) ? smin : sval;
860  smax = ( smax > sval ) ? smax : sval;
861  cmin = ( cmin < cval ) ? cmin : cval;
862  cmax = ( cmax > cval ) ? cmax : cval;
863  }
864 
865  if ( dsize == 1 )
866  {
867  smin *= 0.95;
868  smax *= 1.05;
869  cmin *= 0.95;
870  cmax *= 1.05;
871  }
872 
873  double rdif = ( smax - smin ) / 20.0;
874  smin -= rdif;
875  smax += rdif;
876  rdif = ( cmax - cmin ) / 20.0;
877  cmin -= rdif;
878  cmax += rdif;
879  smin = ( smin > 0.0 ) ? smin : 0.0;
880  cmin = ( cmin > 0.0 ) ? cmin : 0.0;
881 
882  QwtPlotGrid* data_grid = us_grid( data_plot );
883  data_grid->enableYMin( true );
884  data_grid->enableY( true );
885  data_grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(),
886  0, Qt::DashLine ) );
887  data_grid->attach( data_plot );
888 
889  QwtPlotCurve *data_curv = us_curve( data_plot, "distro" );
890  data_curv->setData( x, y, nn );
891  data_curv->setPen( QPen( Qt::yellow, 3, Qt::SolidLine ) );
892  data_curv->setStyle( QwtPlotCurve::Sticks );
893 
894  data_plot->setAxisAutoScale( QwtPlot::xBottom );
895  data_plot->setAxisAutoScale( QwtPlot::yLeft );
896  data_plot->enableAxis( QwtPlot::yRight, false );
897  data_plot->setAxisTitle( QwtPlot::xBottom, xa_title );
898  data_plot->setAxisTitle( QwtPlot::yLeft, tr( "Partial Concentration" ) );
899  data_plot->setAxisScale( QwtPlot::xBottom, smin, smax );
900  data_plot->setAxisScale( QwtPlot::yLeft, cmin, cmax );
901 
902  data_plot->replot();
903 
904  pb_reset ->setEnabled( true );
905  pb_autassb->setEnabled( false );
906  manbuks = true;
907 }
908 
909 // plot data 2-D
911 {
912  data_plot->detachItems();
913 
914  data_plot->setCanvasBackground( Qt::black );
915  pick->setTrackerPen( QColor( Qt::white ) );
916 
917  int dsize = sdistro->size();
918  double* x = new double[ dsize ];
919  double* y = new double[ dsize ];
920  double smin = 1.0e30;
921  double smax = -1.0e30;
922  double kmin = 1.0e30;
923  double kmax = -1.0e30;
924 
925  for ( int jj = 0; jj < dsize; jj++ )
926  {
927  double sval = sdistro->at( jj ).s;
928  double kval = sdistro->at( jj ).k;
929  x[ jj ] = sval;
930  y[ jj ] = kval;
931  smin = qMin( smin, sval );
932  smax = qMax( smax, sval );
933  kmin = qMin( kmin, kval );
934  kmax = qMax( kmax, kval );
935  }
936 
937  if ( dsize == 1 )
938  {
939  smin *= 0.95;
940  smax *= 1.05;
941  kmin *= 0.95;
942  kmax *= 1.05;
943  }
944 
945  double rdif = ( smax - smin ) / 20.0;
946  smin -= rdif;
947  smax += rdif;
948  rdif = ( kmax - kmin ) / 20.0;
949  kmin -= rdif;
950  kmax += rdif;
951  smin = ( smin > 0.0 ) ? smin : 0.0;
952  kmin = ( kmin > 0.0 ) ? kmin : 0.0;
953 
954  QwtPlotGrid* data_grid = us_grid( data_plot );
955  data_grid->enableYMin( true );
956  data_grid->enableY( true );
957  data_grid->setMajPen( QPen( US_GuiSettings::plotMajGrid(),
958  0, Qt::DashLine ) );
959  data_grid->attach( data_plot );
960 
961  QwtPlotCurve *data_curv = us_curve( data_plot, "distro" );
962  QwtSymbol symbol;
963 
964  symbol.setStyle( QwtSymbol::Ellipse );
965  symbol.setPen( QPen( Qt::red ) );
966  symbol.setBrush( QBrush( Qt::yellow ) );
967  if ( dsize < 100 && dsize > 50 )
968  symbol.setSize( 8 );
969  else if ( dsize < 50 && dsize > 20 )
970  symbol.setSize( 10 );
971  else if ( dsize < 21 )
972  symbol.setSize( 12 );
973  else if ( dsize > 100 )
974  symbol.setSize( 6 );
975 
976  data_curv->setStyle( QwtPlotCurve::NoCurve );
977  data_curv->setSymbol( symbol );
978  data_curv->setData( x, y, dsize );
979 
980  delete [] x;
981  delete [] y;
982  data_plot->setAxisAutoScale( QwtPlot::xBottom );
983  data_plot->setAxisAutoScale( QwtPlot::yLeft );
984  data_plot->enableAxis( QwtPlot::yRight, false );
985  data_plot->setAxisTitle( QwtPlot::xBottom, xa_title );
986  data_plot->setAxisTitle( QwtPlot::yLeft, ya_title );
987  data_plot->setAxisTitle( QwtPlot::yRight, tr( "Partial Concentration" ) );
988  data_plot->axisTitle( QwtPlot::yRight ).setFont(
989  data_plot->axisTitle( QwtPlot::yLeft ).font() );
990  data_plot->setAxisScale( QwtPlot::xBottom, smin, smax );
991  data_plot->setAxisScale( QwtPlot::yLeft, kmin, kmax );
992 
993  data_plot->replot();
994 
995  pb_reset->setEnabled( true );
996  pb_autassb->setEnabled( !monte_carlo );
997 }
998 
999 // plot data 3-D
1001 {
1002  data_plot->detachItems();
1003  QColor bg = colormap->color1();
1004 
1005  data_plot->setCanvasBackground( bg );
1006 
1007  int csum = bg.red() + bg.green() + bg.blue();
1008  pick->setTrackerPen( QPen( ( csum > 600 ) ? QColor( Qt::black ) :
1009  QColor( Qt::white ) ) );
1010 
1011  QString tstr = run_name + "\n" + analys_name + "\n (" + method + ")";
1012  data_plot->setTitle( tstr );
1013 
1014  // set up spectrogram data
1015  d_spectrogram = new QwtPlotSpectrogram();
1016  d_spectrogram->setData( US_SpectrogramData() );
1017  d_spectrogram->setColorMap( *colormap );
1018 
1019  US_SpectrogramData& spec_dat = (US_SpectrogramData&)d_spectrogram->data();
1020 
1021  QwtDoubleRect drect;
1022 
1023  if ( auto_lim )
1024  drect = QwtDoubleRect( 0.0, 0.0, 0.0, 0.0 );
1025  else
1026  {
1027  double zmin = sdistro->at( 0 ).c;
1028  double zmax = zmin;
1029  drect = QwtDoubleRect( plxmin, plymin,
1030  ( plxmax - plxmin ), ( plymax - plymin ) );
1031 
1032  for ( int jj = 0; jj < sdistro->size(); jj++ )
1033  {
1034  zmin = qMin( zmin, sdistro->at( jj ).c );
1035  zmax = qMax( zmax, sdistro->at( jj ).c );
1036  }
1037 
1038  spec_dat.setZRange( zmin, zmax );
1039  }
1040 
1041  spec_dat.setRastRanges( xreso, yreso, resolu, zfloor, drect );
1042  spec_dat.setRaster( sdistro );
1043 
1044  d_spectrogram->attach( data_plot );
1045 
1046  // set color map and axis settings
1047  QwtScaleWidget *rightAxis = data_plot->axisWidget( QwtPlot::yRight );
1048  rightAxis->setColorBarEnabled( true );
1049  rightAxis->setColorMap( spec_dat.range(), d_spectrogram->colorMap() );
1050  data_plot->setAxisTitle( QwtPlot::xBottom, xa_title );
1051  data_plot->setAxisTitle( QwtPlot::yLeft, ya_title );
1052  data_plot->setAxisTitle( QwtPlot::yRight, tr( "Partial Concentration" ) );
1053  data_plot->axisTitle( QwtPlot::yRight ).setFont(
1054  data_plot->axisTitle( QwtPlot::yLeft ).font() );
1055  data_plot->setAxisScale( QwtPlot::yRight,
1056  spec_dat.range().minValue(), spec_dat.range().maxValue() );
1057  data_plot->enableAxis( QwtPlot::yRight );
1058 
1059  if ( auto_lim )
1060  { // auto limits
1061  data_plot->setAxisAutoScale( QwtPlot::yLeft );
1062  data_plot->setAxisAutoScale( QwtPlot::xBottom );
1063  }
1064  else
1065  { // manual limits
1066  data_plot->setAxisScale( QwtPlot::xBottom, plxmin, plxmax );
1067  data_plot->setAxisScale( QwtPlot::yLeft, plymin, plymax );
1068  }
1069 
1070  data_plot->replot();
1071 
1072  pb_reset ->setEnabled( true );
1073  pb_autassb->setEnabled( !monte_carlo );
1074 }
1075 
1076 // update pseudo-3d resolution factor
1078 {
1079  resolu = dval;
1080 }
1081 
1082 // update raster x resolution
1084 {
1085  xreso = dval;
1086 }
1087 
1088 // update raster y resolution
1090 {
1091  yreso = dval;
1092 }
1093 
1094 // update Z (frequency) floor percent
1096 {
1097  zfloor = dval;
1098 }
1099 
1100 // update number of initial solutes
1102 {
1103  nisols = qRound( dval );
1104 }
1105 
1106 // update width in s of buckets
1108 {
1109  wxbuck = dval;
1110 }
1111 
1112 // update height in f/f0 of buckets
1114 {
1115  hybuck = dval;
1116 }
1117 
1118 // update plot limit s min
1120 {
1121  plxmin = dval;
1122 }
1123 
1124 // update plot limit s max
1126 {
1127  plxmax = dval;
1128 
1129  if ( attr_x == ATTR_W )
1130  { // For MW, use logarithmic steps
1131  double rinc = pow( 10.0, qRound( log10( dval ) ) - 2.0 );
1132  ct_plxmin->setStep( rinc );
1133  ct_plxmax->setStep( rinc );
1134 // ct_plxmax->setRange( 0.0, 1.0E+8, rinc );
1135  }
1136 }
1137 
1138 // update plot limit f/f0 min
1140 {
1141  plymin = dval;
1142 }
1143 
1144 // update plot limit f/f0 max
1146 {
1147  plymax = dval;
1148 
1149  if ( attr_y == ATTR_W )
1150  { // For MW, use logarithmic steps
1151  double rinc = pow( 10.0, qRound( log10( dval ) ) - 2.0 );
1152  ct_plymin->setStep( rinc );
1153  ct_plymax->setStep( rinc );
1154 // ct_plymax->setRange( 0.0, 1.0E+8, rinc );
1155  }
1156 }
1157 
1158 // select automatic plot limits
1160 {
1161  auto_lim = ck_autlim->isChecked();
1162  ct_plymin->setEnabled( !auto_lim );
1163  ct_plymax->setEnabled( !auto_lim );
1164  ct_plxmin->setEnabled( !auto_lim );
1165  ct_plxmax->setEnabled( !auto_lim );
1166  if ( auto_lim )
1167  {
1168  set_limits();
1169  }
1170 
1171  wxbuck = ( plxmax - plxmin ) / 20.0;
1172  hybuck = ( plymax - plymin ) / 20.0;
1173  double rmax = wxbuck * 10.0;
1174  double rinc = pow( 10.0, (double)( (int)( log10( rmax ) - 3.0 ) ) );
1175  ct_wxbuck->disconnect( );
1176  ct_wxbuck->setRange( 0.0, rmax, rinc );
1177  ct_wxbuck->setValue( wxbuck );
1178  ct_hybuck->setValue( hybuck );
1179  connect( ct_wxbuck, SIGNAL( valueChanged( double ) ),
1180  this, SLOT( update_wxbuck( double ) ) );
1181 }
1182 
1183 // select 1-dimensional plot
1185 {
1186  plot_dim = 1;
1187  ck_2dplot->disconnect();
1188  ck_3dplot->disconnect();
1189  ck_2dplot->setChecked( false );
1190  ck_3dplot->setChecked( false );
1191 
1192  ck_1dplot->setEnabled( false );
1193  ck_2dplot->setEnabled( true );
1194  ck_3dplot->setEnabled( true );
1195 
1196  connect( ck_2dplot, SIGNAL( clicked() ),
1197  this, SLOT( select_plot2d() ) );
1198  connect( ck_3dplot, SIGNAL( clicked() ),
1199  this, SLOT( select_plot3d() ) );
1200 
1201  replot_data();
1202 
1203  pb_mandrsb->setEnabled( false );
1204  pb_autassb->setEnabled( false );
1205  manbuks = true;
1206 }
1207 
1208 // select 2-dimensional plot
1210 {
1211  plot_dim = 2;
1212  ck_1dplot->disconnect();
1213  ck_3dplot->disconnect();
1214  ck_1dplot->setChecked( false );
1215  ck_3dplot->setChecked( false );
1216 
1217  ck_1dplot->setEnabled( true );
1218  ck_2dplot->setEnabled( false );
1219  ck_3dplot->setEnabled( true );
1220 
1221  connect( ck_1dplot, SIGNAL( clicked() ),
1222  this, SLOT( select_plot1d() ) );
1223  connect( ck_3dplot, SIGNAL( clicked() ),
1224  this, SLOT( select_plot3d() ) );
1225 
1226  replot_data();
1227 
1228  pb_mandrsb->setEnabled( true );
1229  pb_autassb->setEnabled( !monte_carlo );
1230 }
1231 
1232 // select 3-dimensional plot
1234 {
1235  plot_dim = 3;
1236  ck_1dplot->disconnect();
1237  ck_2dplot->disconnect();
1238  ck_3dplot->disconnect();
1239  ck_1dplot->setChecked( false );
1240  ck_2dplot->setChecked( false );
1241 
1242  ck_1dplot->setEnabled( true );
1243  ck_2dplot->setEnabled( true );
1244  ck_3dplot->setEnabled( false );
1245 
1246  connect( ck_1dplot, SIGNAL( clicked() ),
1247  this, SLOT( select_plot1d() ) );
1248  connect( ck_2dplot, SIGNAL( clicked() ),
1249  this, SLOT( select_plot2d() ) );
1250  connect( ck_3dplot, SIGNAL( clicked() ),
1251  this, SLOT( select_plot3d() ) );
1252 
1253  replot_data();
1254 
1255  pb_mandrsb->setEnabled( true );
1256  pb_autassb->setEnabled( !monte_carlo );
1257 }
1258 
1259 // load the solute distribution from a file or from DB
1261 {
1262  S_Solute sol_sk;
1263  S_Solute sol_xy;
1264  US_Model model;
1265  QString mdesc;
1266  bool loadDB = dkdb_cntrls->db();
1267  double smin = 1e+39;
1268  double smax = 1e-39;
1269  double kmin = 1e+39;
1270  double kmax = 1e-39;
1271  double wmin = 1e+39;
1272  double wmax = 1e-39;
1273  double vmin = 1e+39;
1274  double vmax = 1e-39;
1275  double dmin = 1e+39;
1276  double dmax = 1e-39;
1277  double fmin = 1e+39;
1278  double fmax = 1e-39;
1279 
1280  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1281  US_ModelLoader dialog( loadDB, mfilter, model, mdesc, pfilts );
1282  dialog.move( this->pos() + QPoint( 200, 200 ) );
1283 
1284  connect( &dialog, SIGNAL( changed( bool ) ),
1285  this, SLOT( update_disk_db( bool ) ) );
1286  QApplication::restoreOverrideCursor();
1287 
1288  QString mfnam;
1289  QString sep;
1290  QString aiters;
1291 
1292  if ( dialog.exec() != QDialog::Accepted )
1293  return;
1294 
1295 
1296 DbgLv(1) << "LOAD ACCEPT Description:\n " << mdesc;
1297  sep = mdesc.left( 1 );
1298  mfnam = mdesc.section( sep, 2, 2 );
1299  aiters = mdesc.section( sep, 6, 6 );
1300 
1301  if ( mfnam.isEmpty() )
1302  { // From db: make ID the "filename"
1303  mfnam = "db ID " + mdesc.section( sep, 4, 4 );
1304  }
1305 
1306  else
1307  { // From disk: use base file name
1308  mfnam = QFileInfo( mfnam ).baseName();
1309  }
1310 
1311  if ( model.components.size() < 1 )
1312  {
1313 DbgLv(0) << " NO Model components";
1314  return;
1315  }
1316 
1317  // insure all model coefficient properties are set
1318  if ( ! model.update_coefficients() )
1319  {
1320  DbgLv(0) << "*** Unable to recalculate coefficient values ***";
1321  }
1322 
1323  // parse model information from its description
1324  mdesc = mdesc.section( sep, 1, 1 );
1325  method = model.typeText();
1326  method = mdesc.contains( "-CG" )
1327  ? method.replace( "2DSA", "2DSA-CG" ) : method;
1328  run_name = mdesc.section( ".", 0, -3 );
1329  QString asys = mdesc.section( ".", -2, -2 );
1330  analys_name = asys.section( "_", 0, 1 ) + "_"
1331  + asys.section( "_", 3, 4 );
1332 
1333  if ( method == "Manual" || method == "CUSTOMGRID" )
1334  {
1335  int jj = mdesc.indexOf( ".model" );
1336  mdesc = ( jj < 1 ) ? mdesc : mdesc.left( jj );
1337  run_name = mdesc + ".0Z280";
1338  analys_name = "e00_a00_" + method + "_local";
1339  }
1340 
1341  monte_carlo = model.monteCarlo;
1342  mc_iters = monte_carlo ? aiters.toInt() : 1;
1343  editGUID = model.editGUID;
1344 DbgLv(1) << "MC" << monte_carlo << " iters" << mc_iters;
1345 
1346  sk_distro.clear();
1347  xy_distro.clear();
1348 
1349  resetSb();
1350 
1351  QString tstr = run_name+ "\n" + analys_name + "\n (" + method + ")";
1352  data_plot->setTitle( tstr );
1353 
1354  // read in and set distribution s,c,k,d values
1355  if ( model.analysis != US_Model::COFS )
1356  {
1357  for ( int jj = 0; jj < model.components.size(); jj++ )
1358  {
1359  US_Model::calc_coefficients( model.components[ jj ] );
1360 
1361  sol_sk.s = model.components[ jj ].s * 1.0e13;
1362  sol_sk.k = model.components[ jj ].f_f0;
1363  sol_sk.c = model.components[ jj ].signal_concentration;
1364  sol_sk.w = model.components[ jj ].mw;
1365  sol_sk.v = model.components[ jj ].vbar20;
1366  sol_sk.d = model.components[ jj ].D;
1367  sol_sk.f = model.components[ jj ].f;
1368 
1369  sol_xy = sol_sk;
1370  sol_xy.s = ( attr_x == ATTR_S ) ? sol_sk.s : sol_xy.s;
1371  sol_xy.s = ( attr_x == ATTR_K ) ? sol_sk.k : sol_xy.s;
1372  sol_xy.s = ( attr_x == ATTR_W ) ? sol_sk.w : sol_xy.s;
1373  sol_xy.s = ( attr_x == ATTR_V ) ? sol_sk.v : sol_xy.s;
1374  sol_xy.s = ( attr_x == ATTR_D ) ? sol_sk.d : sol_xy.s;
1375  sol_xy.s = ( attr_x == ATTR_F ) ? sol_sk.f : sol_xy.s;
1376  sol_xy.k = ( attr_y == ATTR_S ) ? sol_sk.s : sol_xy.k;
1377  sol_xy.k = ( attr_y == ATTR_K ) ? sol_sk.k : sol_xy.k;
1378  sol_xy.k = ( attr_y == ATTR_W ) ? sol_sk.w : sol_xy.k;
1379  sol_xy.k = ( attr_y == ATTR_V ) ? sol_sk.v : sol_xy.k;
1380  sol_xy.k = ( attr_y == ATTR_D ) ? sol_sk.d : sol_xy.k;
1381  sol_xy.k = ( attr_y == ATTR_F ) ? sol_sk.f : sol_xy.k;
1382  sol_xy.si = sol_sk.s;
1383  sol_xy.ki = sol_sk.k;
1384 
1385  smin = qMin( smin, sol_sk.s );
1386  smax = qMax( smax, sol_sk.s );
1387  kmin = qMin( kmin, sol_sk.k );
1388  kmax = qMax( kmax, sol_sk.k );
1389  wmin = qMin( wmin, sol_sk.w );
1390  wmax = qMax( wmax, sol_sk.w );
1391  vmin = qMin( vmin, sol_sk.v );
1392  vmax = qMax( vmax, sol_sk.v );
1393  dmin = qMin( dmin, sol_sk.d );
1394  dmax = qMax( dmax, sol_sk.d );
1395  fmin = qMin( fmin, sol_sk.f );
1396  fmax = qMax( fmax, sol_sk.f );
1397 //DbgLv(2) << "Solute jj s w k c d" << jj << sol_s.s << sol_w.s << sol_s.k
1398 // << sol_s.c << sol_s.d << " vb" << model.components[jj].vbar20;
1399 
1400  sk_distro << sol_sk;
1401  xy_distro << sol_xy;
1402  }
1403 
1404  // sort and reduce distributions
1405  sdistro = &xy_distro;
1406  psdsiz = sdistro->size();
1407  sort_distro( sk_distro, false );
1408  sort_distro( xy_distro, true );
1409 DbgLv(1) << "Solute psdsiz sdsiz xdsiz" << psdsiz << sk_distro.size()
1410  << xy_distro.size();
1411 for ( int jj=0;jj<sk_distro.size();jj++ ) {
1412  DbgLv(2) << " jj" << jj << " s k" << sk_distro[jj].s << sk_distro[jj].k
1413  << " w v" << sk_distro[jj].w << sk_distro[jj].v; }
1414  }
1415 
1416  // Determine which attribute is fixed
1417  if ( equivalent( vmin, vmax, 0.001 ) )
1418  attr_z = ATTR_V;
1419  else if ( equivalent( kmin, kmax, 0.001 ) )
1420  attr_z = ATTR_K;
1421  else if ( equivalent( smin, smax, 0.001 ) )
1422  attr_z = ATTR_S;
1423  else if ( equivalent( wmin, wmax, 0.001 ) )
1424  attr_z = ATTR_W;
1425  else if ( equivalent( dmin, dmax, 0.001 ) )
1426  attr_z = ATTR_D;
1427  else if ( equivalent( fmin, fmax, 0.001 ) )
1428  attr_z = ATTR_F;
1429 
1430  if ( attr_x != ATTR_V && attr_y != ATTR_V && attr_z != ATTR_V )
1431  { // No attribute is vbar, so use vbar as the default X or Y
1432  int attrv = ATTR_V;
1433 
1434  if ( attr_y == attr_z )
1435  {
1436  rb_y_vbar->setChecked( true );
1437  select_y_axis( attrv );
1438  }
1439  else
1440  {
1441  rb_x_vbar->setChecked( true );
1442  select_x_axis( attrv );
1443  }
1444  }
1445 
1446  QStringList attrs;
1447  attrs << "s" << "f/f0" << "MW" << "vbar" << "D" << "f";
1448  QString s_attr = attrs[ attr_z ];
1449 
1450  if ( auto_lim )
1451  {
1452  set_limits();
1453 
1454  ct_plymin->setEnabled( false );
1455  ct_plymax->setEnabled( false );
1456  ct_plxmin->setEnabled( false );
1457  ct_plxmax->setEnabled( false );
1458  }
1459  else
1460  {
1461  plxmin = ct_plxmin->value();
1462  plxmax = ct_plxmax->value();
1463  plymin = ct_plymin->value();
1464  plymax = ct_plymax->value();
1465  }
1466  data_plot->setAxisScale( QwtPlot::xBottom, plxmin, plxmax );
1467  data_plot->setAxisScale( QwtPlot::yLeft, plymin, plymax );
1468 
1469  pb_resetsb->setEnabled( true );
1470 
1471  nisols = sdistro->size();
1472  s_attr = "\"" + s_attr + "\".";
1473  dfilname = "(" + mfnam + ") " + mdesc;
1474  stdfline = " " + dfilname;
1475  stfxline = tr( "The components fixed attribute is " ) + s_attr;
1476  stnpline = tr( "The number of distribution points is %1" )
1477  .arg( nisols );
1478  if ( nisols != psdsiz )
1479  stnpline += tr( "\n (reduced from %1)" ).arg( psdsiz );
1480 
1481  te_status->setText( stcmline + "\n" + stdiline + "\n"
1482  + stdfline + "\n" + stfxline + "\n" + stnpline + "." );
1483 
1484  replot_data();
1485 
1487 
1488  nibuks = 0;
1489  wxbuck = ( plxmax - plxmin ) / 20.0;
1490  hybuck = ( plymax - plymin ) / 20.0;
1491  ct_wxbuck->setValue( wxbuck );
1492  ct_hybuck->setValue( hybuck );
1493  ct_nisols->setValue( double( nisols ) );
1494  ct_wxbuck->setEnabled( true );
1495  ct_hybuck->setEnabled( true );
1496  pb_refresh->setEnabled( true );
1497  pb_mandrsb->setEnabled( plot_dim != 1 );
1498 }
1499 
1500 // load the color map from a file
1502 {
1503  QString filter = tr( "Color Map files (*cm-*.xml);;" )
1504  + tr( "Any XML files (*.xml);;" )
1505  + tr( "Any files (*)" );
1506 
1507  // get an xml file name for the color map
1508  QString fname = QFileDialog::getOpenFileName( this,
1509  tr( "Load Color Map File" ),
1510  US_Settings::etcDir(), filter, 0, 0 );
1511 
1512  if ( fname.isEmpty() )
1513  return;
1514 
1515  // get the map from the file
1516  QList< QColor > cmcolor;
1517  QList< double > cmvalue;
1518 
1519  US_ColorGradIO::read_color_steps( fname, cmcolor, cmvalue );
1520  colormap = new QwtLinearColorMap( cmcolor.first(), cmcolor.last() );
1521 
1522  for ( int jj = 1; jj < cmvalue.size() - 1; jj++ )
1523  {
1524  colormap->addColorStop( cmvalue.at( jj ), cmcolor.at( jj ) );
1525  }
1526  QFileInfo fi( fname );
1527  cmapname = tr( "Color Map: " ) + fi.baseName();
1528 
1529  stcmline = cmapname;
1530  te_status->setText( stcmline + "\n" + stdiline + "\n"
1531  + stdfline + "\n" + stfxline + "\n" + stnpline );
1532 
1533  replot_data();
1534 }
1535 
1536 // set plot x,y limits
1538 {
1539  double smin = 1.0e30;
1540  double smax = -1.0e30;
1541  double kmin = 1.0e30;
1542  double kmax = -1.0e30;
1543  double sinc;
1544  double kinc;
1545 
1546  resetSb();
1547  sdistro = &xy_distro;
1548 
1550 
1551  data_plot->setAxisTitle( QwtPlot::xBottom, xa_title );
1552  data_plot->setAxisTitle( QwtPlot::yLeft, ya_title );
1553 
1554  // find min,max for S distributions
1555  for ( int jj = 0; jj < sdistro->size(); jj++ )
1556  {
1557  double sval = sdistro->at( jj ).s;
1558  double kval = sdistro->at( jj ).k;
1559  smin = qMin( smin, sval );
1560  smax = qMax( smax, sval );
1561  kmin = qMin( kmin, kval );
1562  kmax = qMax( kmax, kval );
1563  }
1564 DbgLv(1) << "SL: distr skmin,max" << smin << smax << kmin << kmax;
1565 
1566  // adjust minima, maxima
1567  sinc = ( smax - smin ) / 10.0;
1568  kinc = ( kmax - kmin ) / 10.0;
1569 DbgLv(1) << "SL: adj sinc kinc" << sinc << kinc;
1570  sinc = ( sinc == 0.0 || sdistro->size() == 1 ) ? ( smin * 0.05 ) : sinc;
1571  kinc = ( kinc == 0.0 || sdistro->size() == 1 ) ? ( kmin * 0.05 ) : kinc;
1572 DbgLv(1) << "SL: adj sinc kinc" << sinc << kinc;
1573 
1574  smin -= sinc;
1575  smax += sinc;
1576  kmin -= kinc;
1577  kmax += kinc;
1578 DbgLv(1) << "SL: adj smin,max" << smin << smax
1579  << "kmin,max" << kmin << kmax;
1580 
1581  if ( auto_lim )
1582  { // Set auto limits
1583  sinc = pow( 10.0, qFloor( log10( smax ) ) - 3.0 );
1584  kinc = pow( 10.0, qFloor( log10( kmax ) ) - 3.0 );
1585 DbgLv(1) << "SL: aut min,inc" << smax << sinc << kmax << kinc;
1586 
1587  // Make x,y limits multiples of reasonable values
1588  if ( equivalent( smin, smax, 0.001 ) )
1589  {
1590  smin -= sinc;
1591  smax += sinc;
1592  }
1593  if ( equivalent( kmin, kmax, 0.001 ) )
1594  {
1595  kmin -= kinc;
1596  kmax += kinc;
1597  }
1598  smin = qFloor( smin / sinc ) * sinc;
1599  smax = qFloor( smax / sinc ) * sinc + sinc;
1600  smin = ( attr_x != ATTR_S ) ? qMax( smin, 0.0 ) : smin;
1601  smin = ( attr_x == ATTR_K ) ? qMax( smin, 0.8 ) : smin;
1602  kmin = qFloor( kmin / kinc ) * kinc;
1603  kmax = qFloor( kmax / kinc ) * kinc + kinc;
1604  kmin = ( attr_y != ATTR_S ) ? qMax( kmin, 0.0 ) : kmin;
1605  kmin = ( attr_y == ATTR_K ) ? qMax( kmin, 0.8 ) : kmin;
1606 DbgLv(1) << "SL: auto smin,max,inc" << smin << smax << sinc
1607  << "kmin,max,inc" << kmin << kmax << kinc;
1608 
1609  ct_plxmin->setValue( smin );
1610  ct_plxmax->setValue( smax );
1611  ct_plymin->setValue( kmin );
1612  ct_plymax->setValue( kmax );
1613 
1614  plxmin = smin;
1615  plxmax = smax;
1616  plymin = kmin;
1617  plymax = kmax;
1618  }
1619  else
1620  {
1621  plxmin = ct_plxmin->value();
1622  plxmax = ct_plxmax->value();
1623  plymin = ct_plymin->value();
1624  plymax = ct_plymax->value();
1625  }
1626 
1627  // Set bucket width,height values
1628  wxbuck = ( plxmax - plxmin ) / 20.0;
1629  hybuck = ( plymax - plymin ) / 20.0;
1630  ct_wxbuck->disconnect( );
1631  ct_hybuck->disconnect( );
1632  int spwr = qRound( log10( wxbuck ) );
1633  int kpwr = qRound( log10( hybuck ) );
1634  smax = pow( 10.0, spwr + 3 );
1635  kmax = pow( 10.0, kpwr + 3 );
1636  sinc = pow( 10.0, spwr - 3 );
1637  kinc = pow( 10.0, kpwr - 3 );
1638  wxbuck = qRound( wxbuck / sinc ) * sinc;
1639  ct_wxbuck->setRange( 0.0, smax, sinc );
1640  ct_wxbuck->setValue( wxbuck );
1641  hybuck = qRound( hybuck / kinc ) * kinc;
1642  ct_wxbuck->setRange( 0.0, kmax, kinc );
1643  ct_hybuck->setValue( hybuck );
1644  connect( ct_wxbuck, SIGNAL( valueChanged( double ) ),
1645  this, SLOT( update_wxbuck( double ) ) );
1646  connect( ct_hybuck, SIGNAL( valueChanged( double ) ),
1647  this, SLOT( update_hybuck( double ) ) );
1648 
1649  // Update help and status text
1650  QString hmsg = tr(
1651  "Now either auto-assign the solute bins, or manually select bins"
1652  " by clicking on a bin vertex, then moving and releasing on the"
1653  " other vertex. If you auto-assign the bins you should first"
1654  " select the number of solute bins you want to use. UltraScan will"
1655  " space the bins proportional to the integral value of each peak,"
1656  " such that each bin contains the same integral value."
1657  " You can select each solute bin from the listbox on the left and"
1658  " modify its size by first changing the bucket dimensions with the"
1659  " respective counters, then double-click on the listbox item."
1660  " You may remove a bin by right-mouse-button clicking on the listbox"
1661  " item and responding/defaulting Yes in the resulting dialog." );
1662 
1663  if ( attr_x != ATTR_V && attr_y != ATTR_V && attr_z != ATTR_V )
1664  hmsg = hmsg + tr(
1665  "\n\nNO SAVE ENABLED: None of X or Y or the fixed-attribute is VBAR." );
1666 
1667  if ( monte_carlo )
1668  hmsg = hmsg + tr(
1669  "\n\nNO AUTOASSIGN ENABLED: Distribution is from a Monte-Carlo." );
1670 
1671  te_pctl_help->setText( hmsg );
1672 
1673 DbgLv(1) << "SL: autoassn xmin,xmax,ymin,ymax" << plxmin << plxmax
1674  << plymin << plymax;
1675  pb_autassb->setEnabled( !monte_carlo );
1676 
1677  int kisols = sdistro->size();
1678  stnpline = tr( "The number of distribution points is %1." )
1679  .arg( kisols );
1680  te_status->setText( stcmline + "\n" + stdiline + "\n"
1681  + stdfline + "\n" + stfxline + "\n" + stnpline );
1682 }
1683 
1684 // Sort distribution solute list by s,k values and optionally reduce
1685 void US_GA_Initialize::sort_distro( QList< S_Solute >& listsols,
1686  bool reduce )
1687 {
1688  int sizi = listsols.size();
1689 
1690  if ( sizi < 2 )
1691  return; // nothing need be done for 1-element list
1692 
1693  // sort distro solute list by s,k values
1694 
1695  qSort( listsols.begin(), listsols.end(), distro_lessthan );
1696 
1697  // check reduce flag
1698 
1699  if ( reduce )
1700  { // skip any duplicates in sorted list
1701  S_Solute sol1;
1702  S_Solute sol2;
1703  QList< S_Solute > reduced;
1704  sol1 = listsols.at( 0 );
1705  reduced.append( sol1 ); // output first entry
1706  int kdup = 0;
1707  int jdup = 0;
1708 
1709  for ( int jj = 1; jj < sizi; jj++ )
1710  { // loop to compare each entry to previous
1711  sol2 = listsols.at( jj ); // solute entry
1712 
1713  if ( sol1.s != sol2.s || sol1.k != sol2.k )
1714  { // not a duplicate, so output to temporary list
1715  reduced.append( sol2 );
1716  jdup = 0;
1717  }
1718 
1719  else
1720  { // duplicate: sum c value
1721 DbgLv(1) << "DUP: sval svpr jj" << sol1.s << sol2.s << jj;
1722  kdup = max( kdup, ++jdup );
1723  qreal f = (qreal)( jdup + 1 );
1724  sol2.c += sol1.c; // sum c value
1725  sol2.s = ( sol1.s * jdup + sol2.s ) / f; // average s,k
1726  sol2.k = ( sol1.k * jdup + sol2.k ) / f;
1727  reduced.replace( reduced.size() - 1, sol2 );
1728  }
1729 
1730  sol1 = sol2; // save entry for next iteration
1731  }
1732 
1733  if ( reduced.size() < sizi )
1734  { // if some reduction happened, replace list with reduced version
1735  //double sc = 1.0 / (double)( kdup + 1 );
1736 
1737  //for ( int ii = 0; ii < reduced.size(); ii++ )
1738  // reduced[ ii ].c *= sc;
1739 
1740  listsols = reduced;
1741  }
1742  }
1743  return;
1744 }
1745 
1746 // set bucket pens for previous and current bin
1748 {
1749  QPen penCR( QColor( Qt::red ), 1, Qt::SolidLine );
1750  QPen penCY( QColor( Qt::yellow), 1, Qt::SolidLine );
1751  QPen penCB( QColor( Qt::blue), 1, Qt::SolidLine );
1752 
1753  // current is always red
1754  cbukpen = penCR;
1755 
1756  // previous is blue for light background, yellow for dark
1757  QColor bg = data_plot->canvasBackground();
1758  int csum = bg.red() + bg.green() + bg.blue();
1759  pbukpen = ( csum > 600 ) ? penCB : penCY;
1760 
1761  return;
1762 }
1763 
1764 // highlight solute bin rectangle in red; previous in yellow or blue
1765 void US_GA_Initialize::highlight_solute( QwtPlotCurve* bc1 )
1766 {
1767  if ( bc1 == NULL )
1768  return;
1769 
1770  if ( nibuks > 0 && pc1 != NULL )
1771  { // re-color previous bucket yellow or blue
1772  pc1->setPen( pbukpen );
1773  }
1774 
1775  // current bucket borders drawn in red
1776  bc1->setPen( cbukpen );
1777 
1778  pc1 = bc1; // save previous bucket curve
1779  return;
1780 }
1781 
1782 // find bucket curve by solute index, then highlight
1784 {
1786  return;
1787 }
1788 
1789 // mouse down: save of first point
1790 void US_GA_Initialize::getMouseDown( const QwtDoublePoint& p )
1791 {
1792  p1 = p; // save the first rubberband point
1793 }
1794 
1795 // mouse up: draw bucket rectangle
1796 void US_GA_Initialize::getMouseUp( const QwtDoublePoint& p )
1797 {
1798  double tx[2];
1799  double ty[2];
1800  QwtPlotCurve* bc1;
1801 
1802  p2 = p; // save the second rubberband point
1803 
1804  // draw the bucket rectangle
1805  bc1 = drawBucketRect( nibuks, p1, p2 );
1806 
1807  // highlight it (and turn off highlight for previous)
1808  highlight_solute( bc1 );
1809 
1810  data_plot->replot();
1811 
1812  // construct and save a bucket entry
1813  tx[0] = p1.x(); // upper,left and lower,right points
1814  ty[0] = p1.y();
1815  tx[1] = p2.x();
1816  ty[1] = p2.y();
1817 
1818  if ( tx[0] > tx[1] ) // insure properly ordered
1819  {
1820  tx[0] = p2.x();
1821  tx[1] = p1.x();
1822  }
1823 
1824  if ( ty[0] > ty[1] )
1825  {
1826  ty[0] = p2.y();
1827  ty[1] = p1.y();
1828  }
1829 
1830  // create bucket rectangle, solute point, and concentration value
1831  QRectF bucr( QPointF( tx[0], ty[1] ), QPointF( tx[1], ty[0] ) );
1832  QPointF tpt( ( tx[0] + tx[1] ) / 2.0, ( ty[0] + ty[1] ) / 2.0 );
1833  QPointF& bucp = tpt;
1834  int sx = soludata->findNearestPoint( bucp );
1835 
1836  if ( sx >= 0 )
1837  { // for solute point nearest to rectangle midpoint
1838  S_Solute sol = sdistro->at( sx );
1839  qreal bucc = sol.c; // get concentrate value
1840 
1841  // add the bucket entry and add a text box entry
1842  soludata->appendBucket( bucr, bucp, bucc, 2 );
1843 
1844  QString txt = soludata->bucketLine( -3 );
1845  lw_sbin_data->addItem( txt );
1846  }
1847 
1848  // bump solute bins count
1849  nibuks++;
1850  ct_nisols->setValue( (double)nibuks );
1851 
1852  pb_save ->setEnabled( attr_x == ATTR_V ||
1853  attr_y == ATTR_V ||
1854  attr_z == ATTR_V );
1855  pb_view ->setEnabled( true );
1856  pb_ckovrlp->setEnabled( nibuks > 1 );
1857  is_saved = false;
1858 }
1859 
1860 // draw a bucket rectangle by index and top-left,bottom-right points
1861 QwtPlotCurve* US_GA_Initialize::drawBucketRect( int sx,
1862  QPointF pt1, QPointF pt2 )
1863 {
1864  double tx[5];
1865  double ty[5];
1866  QwtPlotCurve* bc1;
1867 
1868  tx[0] = pt1.x(); // set 5 points needed to draw rectangle
1869  ty[0] = pt1.y();
1870  tx[1] = pt2.x();
1871  ty[1] = pt1.y();
1872  tx[2] = pt2.x();
1873  ty[2] = pt2.y();
1874  tx[3] = pt1.x();
1875  ty[3] = pt2.y();
1876  tx[4] = pt1.x();
1877  ty[4] = pt1.y();
1878 
1879  // create the bucket rectangle curve
1880  bc1 = us_curve( data_plot, QString( "bucket border %1" ).arg( sx ) );
1881  bc1->setPen( pbukpen );
1882  bc1->setStyle( QwtPlotCurve::Lines );
1883  bc1->setData( tx, ty, 5 );
1884 
1885  return bc1;
1886 }
1887 
1888 // draw a bucket rectangle by index and rectangle
1889 QwtPlotCurve* US_GA_Initialize::drawBucketRect( int sx, QRectF rect )
1890 {
1891  return drawBucketRect( sx, rect.topLeft(), rect.bottomRight() );
1892 }
1893 
1894 // solute bin list row selected by arrow key
1896 {
1897  sclick_sbdata( lw_sbin_data->currentIndex() );
1898 }
1899 
1900 // solute bin list row clicked: highlight bucket
1901 void US_GA_Initialize::sclick_sbdata( const QModelIndex& mx )
1902 {
1903  int sx = mx.row();
1904  bool global = monte_carlo || manbuks;
1905 
1906  highlight_solute( sx );
1907  data_plot->replot();
1908 
1909  if ( rbtn_click )
1910  {
1911  rbtn_click = false;
1912  lw_sbin_data->disconnect();
1913  int binx = sx + 1;
1914  QMessageBox msgBox;
1915  QString msg = tr( "Are you sure you want to delete solute bin %1 ?" )
1916  .arg( binx );
1917  msgBox.setWindowTitle( tr( "GA_Init Solute Bin Delete" ) );
1918  msgBox.setText( msg );
1919  msgBox.setStandardButtons( QMessageBox::No | QMessageBox::Yes );
1920  msgBox.setDefaultButton( QMessageBox::Yes );
1921  if ( msgBox.exec() == QMessageBox::Yes )
1922  {
1923  removeSoluteBin( sx );
1924  }
1925  connect( lw_sbin_data, SIGNAL( clicked( const QModelIndex& ) ),
1926  this, SLOT( sclick_sbdata( const QModelIndex& ) ) );
1927  connect( lw_sbin_data, SIGNAL( doubleClicked( const QModelIndex& ) ),
1928  this, SLOT( dclick_sbdata( const QModelIndex& ) ) );
1929  connect( lw_sbin_data, SIGNAL( currentRowChanged( int ) ),
1930  this, SLOT( newrow_sbdata( int ) ) );
1931 
1932  int rx = qMin( sx, ( nibuks - 1 ) );
1933  if ( rx >= 0 )
1934  {
1935  lw_sbin_data->setCurrentRow( rx );
1936  highlight_solute( rx );
1937  data_plot->replot();
1938  }
1939  }
1940 
1941  else if ( global && sx != sxset )
1942  {
1943  QRectF rect = soludata->bucketRect( sx );
1944  ct_wxbuck->setValue( rect.width() );
1945  ct_hybuck->setValue( rect.height() );
1946  }
1947  sxset = sx;
1948 }
1949 
1950 // solute bin list row double-clicked: change bucket values
1951 void US_GA_Initialize::dclick_sbdata( const QModelIndex& mx )
1952 {
1953  int sx = mx.row();
1954  bool global = monte_carlo || manbuks;
1955  QwtPlotCurve* bc1;
1956  QPointF pt0;
1957 
1958  if ( !global )
1959  {
1960  pt0 = soludata->bucketPoint( sx, false );
1961  }
1962  else
1963  {
1964  QRectF rect = soludata->bucketRect( sx );
1965  QPointF ptl = rect.topLeft();
1966  QPointF pbr = rect.bottomRight();
1967  pt0 = QPointF( ( ptl.x() + pbr.x() ) / 2.0,
1968  ( ptl.y() + pbr.y() ) / 2.0 );
1969  }
1970  sxset = sx;
1971  qreal x1 = pt0.x() - wxbuck / 2.0;
1972  qreal y1 = pt0.y() + hybuck / 2.0;
1973  qreal x2 = pt0.x() + wxbuck / 2.0;
1974  qreal y2 = pt0.y() - hybuck / 2.0;
1975  QPointF pt1( x1, y1 );
1976  QPointF pt2( x2, y2 );
1977  QRectF brect( pt1, pt2 );
1978 
1979  pc1->detach(); // erase old rectangle for this bucket
1980 
1981  changeBucketRect( sx, brect ); // change bucket rectangle
1982 
1983  bc1 = drawBucketRect( sx, pt1, pt2 ); // draw a new rectangle
1984 
1985  pc1 = bc1; // save previous bucket curve
1986  rbtn_click = false;
1987 
1988  data_plot->replot();
1989 
1990  return;
1991 }
1992 
1993 // change the rectangle (vertices) for a bucket
1994 void US_GA_Initialize::changeBucketRect( int sx, QRectF& rect )
1995 {
1996  bucket abuck = soludata->bucketAt( sx );
1997 
1998  QPointF bpnt = soludata->bucketPoint( sx, true );
1999  qreal bconc = soludata->bucketAt( sx ).conc;
2000  int bstat = 0;
2001 
2002  soludata->setBucket( sx, rect, bpnt, bconc, bstat );
2003 
2004  QString line = soludata->bucketLine( sx );
2005  lw_sbin_data->item( sx )->setText( line );
2006 
2007  return;
2008 }
2009 
2010 // find the plot curve in the list of curves
2011 QwtPlotCurve* US_GA_Initialize::bucketCurveAt( int sx )
2012 {
2013  // get title of desired bucket curve and list of all items
2014  QString ctext = QString( "bucket border %1" ).arg( sx );
2015  QwtPlotItemList ilist = data_plot->itemList();
2016 
2017  for ( int jj = 0; jj < ilist.size(); jj++ )
2018  { // test each item for Curve type and matching title
2019  QwtPlotCurve* bc1 = (QwtPlotCurve*)ilist.at( jj );
2020 
2021  if ( bc1->rtti() == QwtPlotItem::Rtti_PlotCurve )
2022  { // right type, so check title
2023  QString itext = bc1->title().text();
2024 
2025  if ( itext.compare( ctext ) == 0 )
2026  { // this is the one we want, return a pointer to the curve
2027  return bc1;
2028  }
2029  }
2030  }
2031 
2032  return (QwtPlotCurve*)NULL;
2033 }
2034 
2035 // erase all bucket curves (option to completely delete )
2037 {
2038 
2039  for ( int jj = 0; jj < nibuks; jj++ )
2040  {
2041  QwtPlotCurve* bc1 = bucketCurveAt( jj );
2042  if ( bc1 != NULL )
2043  {
2044  bc1->detach();
2045 
2046  if ( delflag )
2047  delete bc1;
2048  }
2049  }
2050  nibuks = 0;
2051 
2052  data_plot->replot();
2053 
2054  return;
2055 }
2056 // erase all bucket curves (from plot only)
2058 {
2059  erase_buckets( false );
2060  return;
2061 }
2062 
2063 // filter events to catch right-mouse-button-click on list widget
2064 bool US_GA_Initialize::eventFilter( QObject *obj, QEvent *e )
2065 {
2066  if ( obj == lw_sbin_data &&
2067  e->type() == QEvent::ContextMenu )
2068  {
2069  rbtn_click = true;
2070  return false;
2071  }
2072  else
2073  {
2074  return US_Widgets::eventFilter( obj, e );
2075  }
2076 }
2077 
2078 // Remove a solute bin from data, plot, and list
2080 {
2081  // Remove the solute bin
2082  int bsize = soludata->bucketsCount();
2083  soludata->removeBucketAt( sx );
2084  nibuks = bsize - 1;
2085 
2086  // Reset the buckets plot and list
2087  resetPlotAndList( sx );
2088 }
2089 
2090 // Reset the buckets plot and list after bucket remove or sort
2092 {
2093  // Replace the List Widget contents and redraw bin rectangles
2094  int kibuks = soludata->bucketsCount();
2095  lw_sbin_data->clear();
2096  erase_buckets( );
2097 DbgLv(1) << "rPAL:kibuks nibuks" << kibuks << nibuks;
2098  nibuks = kibuks;
2099  ct_nisols->setValue( (double)nibuks );
2100 
2101  for ( int jj = 0; jj < nibuks; jj++ )
2102  { // Draw the auto-assigned buckets and add lines to list widget
2103  QRectF rect = soludata->bucketRect( jj );
2104  QwtPlotCurve* bc1 = drawBucketRect( jj, rect );
2105  bc1->attach( data_plot );
2106 
2107  lw_sbin_data->addItem( soludata->bucketLine( jj ) );
2108  }
2109 
2110  // Highlight a specified next bucket
2111  hlx = ( hlx >= 0 && hlx < nibuks ) ? hlx : ( nibuks - 1 );
2112 DbgLv(1) << "rPAL: hlx" << hlx;
2113  if ( hlx >= 0 )
2114  {
2115  lw_sbin_data->setCurrentRow( hlx );
2116  highlight_solute( hlx );
2117  }
2118 
2119  data_plot->replot();
2120  qApp->processEvents();
2121 
2122  return;
2123 }
2124 
2125 // Flag whether two values are effectively equal within a given epsilon
2126 bool US_GA_Initialize::equivalent( double a, double b, double eps )
2127 {
2128  return ( qAbs( ( a - b ) / a ) <= eps );
2129 }
2130 
2131 // Reset Disk_DB control whenever data source is changed in any dialog
2133 {
2134  isDB ? dkdb_cntrls->set_db() : dkdb_cntrls->set_disk();
2135 }
2136 // Select a prefilter for model distribution list
2138 {
2139  QString pfmsg;
2140  int nruns = 0;
2141  pfilts.clear();
2142 
2143  US_SelectRuns srdiag( dkdb_cntrls->db(), pfilts );
2144  srdiag.move( this->pos() + QPoint( 200, 200 ) );
2145  connect( &srdiag, SIGNAL( dkdb_changed ( bool ) ),
2146  this, SLOT( update_disk_db( bool ) ) );
2147 
2148  if ( srdiag.exec() == QDialog::Accepted )
2149  nruns = pfilts.size();
2150  else
2151  pfilts.clear();
2152 
2153  if ( nruns == 0 )
2154  pfmsg = tr( "(none chosen)" );
2155 
2156  else if ( nruns > 1 )
2157  pfmsg = tr( "RunID prefilter - %1 run(s)" ).arg( nruns );
2158 
2159  else
2160  pfmsg = tr( "RunID prefilter - 1 run: " ) +
2161  QString( pfilts[ 0 ] ).left( 8 ) + "...";
2162 
2163 DbgLv(1) << "PreFilt: pfilts[0]" << ((nruns>0)?pfilts[0]:"(none)");
2164  le_prefilt->setText( pfmsg );
2165 }
2166 
2167 // View the statistics file produced in a file editor
2169 {
2170 DbgLv(1) << "VIEW";
2171  QString runid = run_name.section( ".", 0, -2 );
2172  if ( runid.startsWith( "Global-" ) )
2173  runid = runid.mid( 7 );
2174  QString trpid = run_name.section( ".", -1, -1 );
2175  QString fdir = US_Settings::resultDir() + "/" + runid;
2176  QString fnsta = "gainit." + trpid + ".sol_integ.stats";
2177  QString fname = fdir + "/" + fnsta;
2178 DbgLv(1) << "VIEW fname" << fname;
2179 
2180  if ( ! is_saved )
2181  { // No save was done, so generate report file
2182  soludata->buildDataMC(); // build it
2183  soludata->reportDataMC( fname, mc_iters ); // report it
2184  is_saved = true;
2185  }
2186 
2187  QFile filei( fname );
2188  if ( filei.open( QIODevice::ReadOnly | QIODevice::Text ) )
2189  {
2190 DbgLv(1) << "VIEW OPENED";
2191  QTextStream ts( &filei );
2192  QString rtext = ts.readAll();
2193  filei.close();
2194 
2195  US_Editor* eddiag = new US_Editor( US_Editor::DEFAULT, true );
2196  eddiag->setWindowTitle( tr( "Statistics File Contents" ) );
2197  eddiag->move( this->pos() + QPoint( 30, 30 ) );
2198  eddiag->resize( 760, 700 );
2199  eddiag->e->setFont( US_Widgets::fixedFont() );
2200  eddiag->e->setPlainText( rtext );
2201 DbgLv(1) << "VIEW eddiag SHOW";
2202  eddiag->show();
2203  }
2204 
2205  else
2206  {
2207 DbgLv(1) << "VIEW OPEN ERROR" << fname;
2208  QMessageBox::critical( this, tr( "File Read Error" ),
2209  tr( "Unable to open file\n\"%1\"\nfor read" ).arg( fname ) );
2210  }
2211 }
2212 
2213 // Select the coordinate for the horizontal axis
2215 {
2216  const QString xlabs[] = { "s", "f/f0", "MW", "vbar", "D", "f" };
2217  const double xvlos[] = { 1.0, 1.0, 2e+4, 0.60, 1e-8, 1e-8 };
2218  const double xvhis[] = { 10.0, 4.0, 1e+5, 0.80, 1e-7, 1e-7 };
2219  const double xmins[] = { -10000.0, 1.0, 0.0, 0.01, 1e-9, 1e-9 };
2220  const double xmaxs[] = { 10000.0, 50.0, 1e+10, 3.00, 1e-5, 1e-5 };
2221  const double xincs[] = { 0.01, 0.01, 1000.0, 0.01, 1e-9, 1e-9 };
2222 
2223  attr_x = ival;
2224  xa_title = anno_title( attr_x );
2225  QString xlab = xlabs[ attr_x ];
2226  double xmin = xmins[ attr_x ];
2227  double xmax = xmaxs[ attr_x ];
2228  double xinc = xincs[ attr_x ];
2229  lb_plxmin->setText( tr( "Plot Limit " ) + xlab + tr( " Minimum:" ) );
2230  lb_plxmax->setText( tr( "Plot Limit " ) + xlab + tr( " Maximum:" ) );
2231  lb_wxbuck->setText( tr( "Width of " ) + xlab + tr( " Bucket:" ) );
2232  ct_plxmin->setRange( xmin, xmax, xinc );
2233  ct_plxmax->setRange( xmin, xmax, xinc );
2234  ct_plxmin->setValue( xvlos[ attr_x ] );
2235  ct_plxmax->setValue( xvhis[ attr_x ] );
2236 
2237  rb_y_s ->setEnabled( attr_x != ATTR_S );
2238  rb_y_ff0 ->setEnabled( attr_x != ATTR_K );
2239  rb_y_mw ->setEnabled( attr_x != ATTR_W );
2240  rb_y_vbar->setEnabled( attr_x != ATTR_V );
2241  rb_y_D ->setEnabled( attr_x != ATTR_D );
2242  rb_y_f ->setEnabled( attr_x != ATTR_F );
2243 
2244  build_xy_distro();
2245 
2246  set_limits();
2247 
2248  replot_data();
2249 }
2250 
2251 // Select the coordinate for the vertical axis
2253 {
2254  const QString ylabs[] = { "s", "f/f0", "MW", "vbar", "D", "f" };
2255  const double yvlos[] = { 1.0, 1.0, 2e+4, 0.60, 1e-8, 1e-8 };
2256  const double yvhis[] = { 10.0, 4.0, 1e+5, 0.80, 1e-7, 1e-7 };
2257  const double ymins[] = { -10000.0, 1.0, 0.0, 0.01, 1e-9, 1e-9 };
2258  const double ymaxs[] = { 10000.0, 50.0, 1e+10, 3.00, 1e-5, 1e-5 };
2259  const double yincs[] = { 0.01, 0.01, 1000.0, 0.01, 1e-9, 1e-9 };
2260 
2261  attr_y = ival;
2262  ya_title = anno_title( attr_y );
2263  QString ylab = ylabs[ attr_y ];
2264  double ymin = ymins[ attr_y ];
2265  double ymax = ymaxs[ attr_y ];
2266  double yinc = yincs[ attr_y ];
2267  lb_plymin->setText( tr( "Plot Limit " ) + ylab + tr( " Minimum:" ) );
2268  lb_plymax->setText( tr( "Plot Limit " ) + ylab + tr( " Maximum:" ) );
2269  lb_hybuck->setText( tr( "Height of " ) + ylab + tr( " Bucket:" ) );
2270  ct_plymin->setRange( ymin, ymax, yinc );
2271  ct_plymax->setRange( ymin, ymax, yinc );
2272  ct_plymin->setValue( yvlos[ attr_y ] );
2273  ct_plymax->setValue( yvhis[ attr_y ] );
2274 
2275  rb_x_s ->setEnabled( attr_y != ATTR_S );
2276  rb_x_ff0 ->setEnabled( attr_y != ATTR_K );
2277  rb_x_mw ->setEnabled( attr_y != ATTR_W );
2278  rb_x_vbar->setEnabled( attr_y != ATTR_V );
2279  rb_x_D ->setEnabled( attr_y != ATTR_D );
2280  rb_x_f ->setEnabled( attr_y != ATTR_F );
2281 
2282  build_xy_distro();
2283 
2284  set_limits();
2285 
2286  replot_data();
2287 }
2288 
2289 // Re-generate the XY version of the current distribution
2291 {
2292  S_Solute sol_sk;
2293  S_Solute sol_xy;
2294  xy_distro.clear();
2295 
2296  for ( int jj = 0; jj < sk_distro.size(); jj++ )
2297  {
2298  sol_sk = sk_distro[ jj ];
2299  sol_xy = sol_sk;
2300  sol_xy.si = sol_sk.s;
2301  sol_xy.ki = sol_sk.k;
2302 
2303  sol_xy.s = ( attr_x == ATTR_S ) ? sol_sk.s : sol_xy.s;
2304  sol_xy.s = ( attr_x == ATTR_K ) ? sol_sk.k : sol_xy.s;
2305  sol_xy.s = ( attr_x == ATTR_W ) ? sol_sk.w : sol_xy.s;
2306  sol_xy.s = ( attr_x == ATTR_V ) ? sol_sk.v : sol_xy.s;
2307  sol_xy.s = ( attr_x == ATTR_D ) ? sol_sk.d : sol_xy.s;
2308  sol_xy.s = ( attr_x == ATTR_F ) ? sol_sk.f : sol_xy.s;
2309  sol_xy.k = ( attr_y == ATTR_S ) ? sol_sk.s : sol_xy.k;
2310  sol_xy.k = ( attr_y == ATTR_K ) ? sol_sk.k : sol_xy.k;
2311  sol_xy.k = ( attr_y == ATTR_W ) ? sol_sk.w : sol_xy.k;
2312  sol_xy.k = ( attr_y == ATTR_V ) ? sol_sk.v : sol_xy.k;
2313  sol_xy.k = ( attr_y == ATTR_D ) ? sol_sk.d : sol_xy.k;
2314  sol_xy.k = ( attr_y == ATTR_F ) ? sol_sk.f : sol_xy.k;
2315 
2316  xy_distro << sol_xy;
2317  }
2318 
2319  sort_distro( xy_distro, true );
2320 }
2321 
2322 // Set annotation title for a plot index
2323 QString US_GA_Initialize::anno_title( int pltndx )
2324 {
2325  QString a_title;
2326 
2327  if ( pltndx == ATTR_S )
2328  a_title = tr( "Sedimentation Coefficient (1e-13)"
2329  " for water at 20" ) + DEGC;
2330  else if ( pltndx == ATTR_K )
2331  a_title = tr( "Frictional Ratio f/f0" );
2332  else if ( pltndx == ATTR_W )
2333  a_title = tr( "Molecular Weight (Dalton)" );
2334  else if ( pltndx == ATTR_V )
2335  a_title = tr( "Vbar at 20" ) + DEGC;
2336  else if ( pltndx == ATTR_D )
2337  a_title = tr( "Diffusion Coefficient" );
2338  else if ( pltndx == ATTR_F )
2339  a_title = tr( "Frictional Coefficient" );
2340 
2341  return a_title;
2342 }
2343