UltraScan III
us_adv_analysis_pc.cpp
Go to the documentation of this file.
1 
3 #include "us_pcsa.h"
4 #include "us_adv_analysis_pc.h"
5 #include "us_mrecs_loader.h"
6 #include "us_settings.h"
7 #include "us_gui_settings.h"
8 #include "us_passwd.h"
9 
10 // constructor: enhanced plot control widget
11 US_AdvAnalysisPc::US_AdvAnalysisPc( QVector< US_ModelRecord >* p_mrs,
12  const int nth, US_SolveSim::DataSet* ds0, QWidget* p )
13  : US_WidgetsDialog( p, 0 )
14 {
15  p_mrecs = p_mrs;
16  nthr = nth;
17  dset0 = ds0;
18  parentw = p;
21 DbgLv(1) << "AA: IN";
22 
23  setObjectName( "US_AdvAnalysisPc" );
24  setPalette( US_GuiSettings::frameColor() );
26  setAttribute( Qt::WA_DeleteOnClose, false );
27  QFontMetrics fmet( font() );
28 
29  // lay out the GUI
30  setWindowTitle( tr( "PCSA Advanced Controls" ) );
31 
32  // Define the layouts
33  mainLayout = new QHBoxLayout( this );
34  finmodelLayout = new QGridLayout( );
35  mreclistLayout = new QGridLayout( );
36 
37  mainLayout->setSpacing ( 2 );
38  mainLayout->setContentsMargins( 2, 2, 2, 2 );
39 
40  mainLayout->addLayout( finmodelLayout );
41  mainLayout->addLayout( mreclistLayout );
42  mainLayout->setStretchFactor( finmodelLayout, 1 );
43  mainLayout->setStretchFactor( mreclistLayout, 1 );
44 DbgLv(1) << "AA: define GUI elements";
45 
46  // Define banners and labels
47  QLabel* lb_fitctrl = us_banner( tr( "Fitting Controls:" ) );
48  QLabel* lb_bfmstat = us_banner( tr( "Best Final Model Status:" ) );
49  QLabel* lb_mrecctrl = us_banner( tr( "Final & Model Records Controls:" ) );
50  QLabel* lb_mrecstat = us_banner( tr( "Model Records Status:" ) );
51  QLabel* lb_curvtype = us_label ( tr( "Curve Type:" ) );
52  QLabel* lb_x_range = us_label ( tr( "X Range:" ) );
53  QLabel* lb_y_range = us_label ( tr( "Y Range:" ) );
54  lb_sigmpar1 = us_label ( tr( "Par 1:" ) );
55  lb_sigmpar2 = us_label ( tr( "Par 2:" ) );
56  lb_y_strpt = us_label ( tr( "Line Y Start Point:" ) );
57  lb_y_endpt = us_label ( tr( "Line Y End Point:" ) );
58  QLabel* lb_crpoints = us_label ( tr( "Curve Resolution Points:" ) );
59  QLabel* lb_mciters = us_label ( tr( "Monte Carlo Iterations:" ) );
60  QLabel* lb_progress = us_label ( tr( "Progress:" ) );
61  QLabel* lb_space1 = us_banner( "" );
62  QLabel* lb_space2 = us_banner( "" );
63 
64  // Define buttons
65  pb_loadmrs = us_pushbutton( tr( "Load Model Records" ) );
66  pb_storemrs = us_pushbutton( tr( "Store Model Records" ) );
67  pb_loadbfm = us_pushbutton( tr( "Load Final Model" ) );
68  pb_storebfm = us_pushbutton( tr( "Store Final Model" ) );
69  pb_resetbfm = us_pushbutton( tr( "Reset Final Model" ) );
70  pb_resetmrs = us_pushbutton( tr( "Reset Model Records" ) );
71  pb_buildbfm = us_pushbutton( tr( "Build Final Model" ) );
72  pb_mciters = us_pushbutton( tr( "Start Monte Carlo" ) );
73  pb_help = us_pushbutton( tr( "Help" ) );
74  pb_cancel = us_pushbutton( tr( "Cancel" ) );
75  pb_accept = us_pushbutton( tr( "Accept" ), false );
76 
77  // Define counters
78  le_x_lower = us_lineedit( "1", -1, true );
79  le_x_upper = us_lineedit( "10", -1, true );
80  le_y_lower = us_lineedit( "1", -1, false );
81  le_y_upper = us_lineedit( "4", -1, false );
82  le_y_strpt = us_lineedit( "1", -1, false );
83  le_y_endpt = us_lineedit( "4", -1, false );
84  le_sigmpar1 = us_lineedit( "1", -1, false );
85  le_sigmpar2 = us_lineedit( "2", -1, false );
86  le_crpoints = us_lineedit( "100", -1, false );
87  le_mciters = us_lineedit( "20", -1, false );
88 
89  // Define combo box
91  cb_curvtype->setMaxVisibleItems( 3 );
92  cb_curvtype->addItem( tr( "Straight Line" ) );
93  cb_curvtype->addItem( tr( "Increasing Sigmoid" ) );
94  cb_curvtype->addItem( tr( "Decreasing Sigmoid" ) );
95  cb_curvtype->addItem( tr( "Horizontal Line [ C(s) ]" ) );
96  cb_curvtype->addItem( tr( "Second-Order Power Law" ) );
97 
98  // Define status text boxes and progress bar
101  b_progress = us_progressBar( 0, 100, 0 );
102  us_setReadOnly( te_bfmstat, true );
103  us_setReadOnly( te_mrecstat, true );
104  te_bfmstat ->setTextColor( Qt::blue );
105  te_mrecstat->setTextColor( Qt::blue );
106 
107  // Lay out the left side, of BFM controls and status
108 DbgLv(1) << "AA: populate finmodelLayout";
109  int row = 0;
110  finmodelLayout->addWidget( lb_fitctrl, row++, 0, 1, 6 );
111  finmodelLayout->addWidget( lb_curvtype, row, 0, 1, 3 );
112  finmodelLayout->addWidget( cb_curvtype, row++, 3, 1, 3 );
113  finmodelLayout->addWidget( lb_x_range, row, 0, 1, 3 );
114  finmodelLayout->addWidget( le_x_lower, row, 3, 1, 1 );
115  finmodelLayout->addWidget( le_x_upper, row++, 4, 1, 1 );
116  finmodelLayout->addWidget( lb_y_range, row, 0, 1, 3 );
117  finmodelLayout->addWidget( le_y_lower, row, 3, 1, 1 );
118  finmodelLayout->addWidget( le_y_upper, row++, 4, 1, 1 );
119  finmodelLayout->addWidget( lb_sigmpar1, row, 0, 1, 3 );
120  finmodelLayout->addWidget( le_sigmpar1, row++, 3, 1, 3 );
121  finmodelLayout->addWidget( lb_sigmpar2, row, 0, 1, 3 );
122  finmodelLayout->addWidget( le_sigmpar2, row++, 3, 1, 3 );
123  finmodelLayout->addWidget( lb_y_strpt, row, 0, 1, 3 );
124  finmodelLayout->addWidget( le_y_strpt, row++, 3, 1, 3 );
125  finmodelLayout->addWidget( lb_y_endpt, row, 0, 1, 3 );
126  finmodelLayout->addWidget( le_y_endpt, row++, 3, 1, 3 );
127  finmodelLayout->addWidget( lb_crpoints, row, 0, 1, 3 );
128  finmodelLayout->addWidget( le_crpoints, row++, 3, 1, 3 );
129  finmodelLayout->addWidget( lb_mciters, row, 0, 1, 3 );
130  finmodelLayout->addWidget( le_mciters, row++, 3, 1, 3 );
131 
132  finmodelLayout->addWidget( lb_bfmstat, row++, 0, 1, 6 );
133  finmodelLayout->addWidget( te_bfmstat, row, 0, 8, 6 );
134  row += 8;
135  finmodelLayout->addWidget( lb_space1, row, 0, 1, 6 );
136 
137  // Lay out the right side, of Model Record controls and status
138 DbgLv(1) << "AA: populate mreclistLayout";
139  row = 0;
140  mreclistLayout->addWidget( lb_mrecctrl, row++, 0, 1, 6 );
141  mreclistLayout->addWidget( pb_loadmrs, row, 0, 1, 3 );
142  mreclistLayout->addWidget( pb_storemrs, row++, 3, 1, 3 );
143  mreclistLayout->addWidget( pb_loadbfm, row, 0, 1, 3 );
144  mreclistLayout->addWidget( pb_storebfm, row++, 3, 1, 3 );
145  mreclistLayout->addWidget( pb_resetbfm, row, 0, 1, 3 );
146  mreclistLayout->addWidget( pb_resetmrs, row++, 3, 1, 3 );
147  mreclistLayout->addWidget( pb_buildbfm, row, 0, 1, 3 );
148  mreclistLayout->addWidget( pb_mciters, row++, 3, 1, 3 );
149 
150  mreclistLayout->addWidget( lb_mrecstat, row++, 0, 1, 6 );
151  mreclistLayout->addWidget( te_mrecstat, row, 0, 8, 6 );
152  mreclistLayout->setRowStretch( row, 2 );
153  row += 8;
154  mreclistLayout->addWidget( lb_progress, row, 0, 1, 1 );
155  mreclistLayout->addWidget( b_progress, row++, 1, 1, 5 );
156  mreclistLayout->addWidget( pb_help, row, 0, 1, 2 );
157  mreclistLayout->addWidget( pb_cancel, row, 2, 1, 2 );
158  mreclistLayout->addWidget( pb_accept, row++, 4, 1, 2 );
159  mreclistLayout->addWidget( lb_space2, row, 0, 1, 6 );
160 
161  cb_curvtype->setEnabled( false );
162 #if 0
163  le_x_lower ->setEnabled( false );
164  le_x_upper ->setEnabled( false );
165  le_y_lower ->setEnabled( false );
166  le_y_upper ->setEnabled( false );
167 #endif
168  int fwidth = fmet.maxWidth();
169  int rheight = le_x_lower->height();
170  int cminw = fwidth * 4;
171  int csizw = cminw + fwidth;
172  le_x_lower->setMinimumWidth( cminw );
173  le_x_upper->setMinimumWidth( cminw );
174  le_y_lower->setMinimumWidth( cminw );
175  le_y_upper->setMinimumWidth( cminw );
176  le_x_lower->resize( csizw, rheight );
177  le_x_upper->resize( csizw, rheight );
178  le_y_lower->resize( csizw, rheight );
179  le_y_upper->resize( csizw, rheight );
180 
181  // Set defaults and status values based on the initial model records
182  mrecs_mc.clear();
183  mrecs = *p_mrecs;
184  nmrecs = mrecs.size();
185  mciters = 0;
186  kciters = 0;
187  bfm0_exists = false;
188  mrs0_exists = false;
189  bfm_new = false;
190  mrs_new = false;
191  mc_done = false;
192  ctype = CTYPE_IS;
193  nisols = 0;
194  ncsols = ( nmrecs > 0 ) ? mrecs[ 0 ].csolutes.size() : 0;
195 
196  if ( ncsols > 0 )
197  { // We are starting with models already computed
198  mrec = mrecs[ 0 ];
199 
200  set_fittings( mrecs );
201 
202 DbgLv(1) << "AA: mr p1 p2 m0 p1 p2" << mrec.par1 << mrec.par2 << mrecs[0].par1
203  << mrecs[0].par2 << " typ ni nc" << ctype << nisols << ncsols;
204 
205  stat_bfm(
206  tr( "An initial best final model, with RMSD of %1,\n"
207  " has been read." ).arg( mrec.rmsd ) );
208 
209  stat_mrecs(
210  tr( "An initial model records list, with %1 fits,\n"
211  " has been read." ).arg( nmrecs ) );
212 
213  mrec0 = mrec; // Save initial model records
214  mrecs0 = mrecs;
215  bfm0_exists = true;
216  mrs0_exists = true;
217  }
218 
219  else
220  { // We are starting with models not yet computed
221  mrec = ( nmrecs > 0 ) ? mrecs[ 0 ] : mrec;
222  mrec0 = mrec; // Save initial model records
223  mrecs0 = mrecs;
224 DbgLv(1) << "AA: nmrecs" << nmrecs << "ncsols" << ncsols;
225  stat_bfm(
226  tr( "No initial best final model has been read" ) );
227  stat_mrecs(
228  tr( "No initial model records list has been read" ) );
229  }
230  ctype = mrec.ctype;
231 
232  // Define connections
233 DbgLv(1) << "AA: connect buttons";
234  connect( cb_curvtype, SIGNAL( currentIndexChanged( int ) ),
235  this, SLOT( curvtypeChanged ( int ) ) );
236 
237 #if 0
238  connect( le_x_lower, SIGNAL( textChanged( const QString& ) ),
239  this, SLOT( slowerChanged( double ) ) );
240  connect( le_x_upper, SIGNAL( textChanged( const QString& ) ),
241  this, SLOT( supperChanged( double ) ) );
242  connect( le_y_lower, SIGNAL( textChanged( const QString& ) ),
243  this, SLOT( klowerChanged( double ) ) );
244  connect( le_y_upper, SIGNAL( textChanged( const QString& ) ),
245  this, SLOT( kupperChanged( double ) ) );
246  connect( le_sigmpar1, SIGNAL( textChanged( const QString& ) ),
247  this, SLOT( sipar1Changed( double ) ) );
248  connect( le_sigmpar2, SIGNAL( textChanged( const QString& ) ),
249  this, SLOT( sipar2Changed( double ) ) );
250  connect( le_crpoints, SIGNAL( textChanged( const QString& ) ),
251  this, SLOT( pointsChanged( double ) ) );
252 #endif
253  connect( le_mciters, SIGNAL( textChanged( const QString& ) ),
254  this, SLOT( mciterChanged( double ) ) );
255 
256  connect( pb_loadmrs, SIGNAL( clicked() ),
257  this, SLOT( load_mrecs() ) );
258  connect( pb_storemrs, SIGNAL( clicked() ),
259  this, SLOT( store_mrecs() ) );
260  connect( pb_loadbfm, SIGNAL( clicked() ),
261  this, SLOT( load_bfm() ) );
262  connect( pb_storebfm, SIGNAL( clicked() ),
263  this, SLOT( store_bfm() ) );
264  connect( pb_resetbfm, SIGNAL( clicked() ),
265  this, SLOT( reset_bfm() ) );
266  connect( pb_resetmrs, SIGNAL( clicked() ),
267  this, SLOT( reset_mrecs() ) );
268  connect( pb_buildbfm, SIGNAL( clicked() ),
269  this, SLOT( build_bfm() ) );
270  connect( pb_mciters, SIGNAL( clicked() ),
271  this, SLOT( start_montecarlo() ) );
272 
273  connect( pb_help, SIGNAL( clicked() ),
274  this, SLOT( help() ) );
275  connect( pb_cancel, SIGNAL( clicked() ),
276  this, SLOT( cancel() ) );
277  connect( pb_accept, SIGNAL( clicked() ),
278  this, SLOT( select() ) );
279 
280  curvtypeChanged( 1 );
281  resize( 780, 400 );
282 DbgLv(1) << "Post-resize size" << size();
283  qApp->processEvents();
284 }
285 
286 // Return state flag from advanced actions and, possibly, MC models
287 int US_AdvAnalysisPc::advanced_results( QVector< US_ModelRecord >* p_mrecsmc )
288 {
289  // Set state flag reflecting new-bfm, new-mrs, montecarlo
290  int state = bfm_new ? msk_bfnew : 0;
291  state = mrs_new ? ( state | msk_mrnew ) : state;
292  state = mc_done ? ( state | msk_mcarl ) : state;
293 DbgLv(1) << "advanced_results - state=" << state;
294 
295  if ( p_mrecsmc != 0 )
296  {
297  if ( mc_done )
298  { // If MonteCarlo was done, return its model records
299  *p_mrecsmc = mrecs_mc;
300  }
301  else
302  { // If MonteCarlo not done or overridden, make sure to clear it
303  p_mrecsmc->clear();
304  }
305  }
306 
307  return state;
308 }
309 
310 // Accept button clicked
312 {
313 DbgLv(1) << "AA:Accept: mrs_new" << mrs_new << "p_mrecs" << p_mrecs;
314  if ( mrs_new && p_mrecs != 0 )
315  { // If model records are new, return them to the caller
316  *p_mrecs = mrecs;
317 DbgLv(1) << "AA:Accept: mr mnmx x y"
318  << p_mrecs->at(0).xmin << p_mrecs->at(0).xmax
319  << p_mrecs->at(0).ymin << p_mrecs->at(0).ymax;
320 DbgLv(1) << "AA:Accept: mr-size mr0-RMSD" << p_mrecs->size()
321  << p_mrecs->at(9).rmsd << "mr0-solsize" << p_mrecs->at(0).csolutes.size();
322  }
323 
324  if ( ! mc_done )
325  { // Insure there is no montecarlo left over if there shouldn't be
326  mrecs_mc.clear();
327  }
328 
329  accept();
330  close();
331 }
332 
333 // Cancel button clicked
335 {
336  bfm_new = false;
337  mrs_new = false;
338  mc_done = false;
339 
340  reject();
341  close();
342 }
343 
344 // Slot to handle a change in curve type
346 {
347 DbgLv(1) << "curvtypeChanged" << ivalue;
348  ctype = ivalue;
349  ctype = ( ivalue == 0 ) ? CTYPE_SL : ctype;
350  ctype = ( ivalue == 1 ) ? CTYPE_IS : ctype;
351  ctype = ( ivalue == 2 ) ? CTYPE_DS : ctype;
352  ctype = ( ivalue == 3 ) ? CTYPE_HL : ctype;
353  ctype = ( ivalue == 4 ) ? CTYPE_2O : ctype;
354  bool is_sigm = ( ctype == CTYPE_IS || ctype == CTYPE_DS );
355  bool is_line = ! is_sigm;
356 
357  lb_sigmpar1->setVisible( is_sigm );
358  le_sigmpar1->setVisible( is_sigm );
359  lb_sigmpar2->setVisible( is_sigm );
360  le_sigmpar2->setVisible( is_sigm );
361  lb_y_strpt ->setVisible( ctype == CTYPE_SL );
362  le_y_strpt ->setVisible( ctype == CTYPE_SL );
363  lb_y_endpt ->setVisible( is_line );
364  le_y_endpt ->setVisible( is_line );
365  if ( ctype == CTYPE_HL )
366  lb_y_endpt->setText( tr( "Line Y End Points:" ) );
367 }
368 
369 #if 0
370 // Slot to handle a change in S lower bound
371 void US_AdvAnalysisPc::slowerChanged( double value )
372 {
373 DbgLv(1) << "slowerChanged" << value;
374 }
375 
376 // Slot to handle a change in S upper bound
377 void US_AdvAnalysisPc::supperChanged( double value )
378 {
379 DbgLv(1) << "supperChanged" << value;
380 }
381 
382 // Slot to handle a change in sigmoid par 1
383 void US_AdvAnalysisPc::sipar1Changed( double value )
384 {
385 DbgLv(1) << "sipar1Changed" << value;
386 }
387 
388 // Slot to handle a change in sigmoid par 2
389 void US_AdvAnalysisPc::sipar2Changed( double value )
390 {
391 DbgLv(1) << "sipar2Changed" << value;
392 }
393 
394 // Slot to handle a change in K(f/f0) lower bound
395 void US_AdvAnalysisPc::klowerChanged( double value )
396 {
397 DbgLv(1) << "klowerChanged" << value;
398 }
399 
400 // Slot to handle a change in K(f/f0) upper bound
401 void US_AdvAnalysisPc::kupperChanged( double value )
402 {
403 DbgLv(1) << "kupperChanged" << value;
404 }
405 
406 // Slot to handle a change in curve points
407 void US_AdvAnalysisPc::pointsChanged( double value )
408 {
409 DbgLv(1) << "pointsChanged" << value;
410 }
411 #endif
412 
413 // Slot to handle a change in monte carlo iterations
415 {
416 DbgLv(1) << "mciterChanged" << value;
417  mciters = (int)value;
418 }
419 
420 // Slot to load a model records list from database or disk
422 {
423  bool loadDB = dset0->requestID.contains( "DB" );
424  QString mrdesc;
425  QString edGUID = dset0->run_data.editGUID;
426  QString dsearch = "";
427  QString runID = dset0->run_data.runID;
428 DbgLv(1) << "load_mrecs loadDB" << loadDB << "reqID" << dset0->requestID;
429 
430  US_MrecsLoader mrldDiag( loadDB, dsearch, mrecs, mrdesc,
431  edGUID, runID );
432 
433  if ( mrldDiag.exec() != QDialog::Accepted )
434  {
435 DbgLv(1) << "mrldDiag.exec==rejected";
436 //*DEBUG*
437 test_db_mrecs();
438 //*DEBUG*
439  return;
440  }
441 
442  // Re-generate curve points for every model record
443  nmrecs = mrecs.size();
444  double xmin = mrecs[ 0 ].xmin;
445  double xmax = mrecs[ 0 ].xmax;
446  double ymin = mrecs[ 0 ].ymin;
447  double ymax = mrecs[ 0 ].ymax;
448 DbgLv(1) << "mrldDiag post-accept xmin xmax ymin ymax"
449  << xmin << xmax << ymin << ymax << "nmrecs" << nmrecs;
450 
451  for ( int mr = 0; mr < nmrecs; mr++ )
452  {
453  mrecs[ mr ].xmin = xmin;
454  mrecs[ mr ].xmax = xmax;
455  mrecs[ mr ].ymin = ymin;
456  mrecs[ mr ].ymax = ymax;
457 
458  curve_isolutes( mrecs[ mr ] );
459  }
460 
461  mrec = mrecs[ 0 ];
462  ctype = mrec.v_ctype;
463  ncsols = mrec.csolutes.size();
464  QString sctype = US_ModelRecord::ctype_text( ctype );
465 
466  // Build the model that goes along with the BFM
467 DbgLv(1) << "pre-bfm-model mr0 rmsd" << mrec.rmsd;
468  bfm_model();
469 DbgLv(1) << "post-bfm-model mr0 rmsd" << mrec.rmsd << mrecs[0].rmsd;
470 
471  stat_bfm(
472  tr( "A new Best Final Model derives from the top spot\n"
473  " of the just-loaded Model Records list.\n"
474  "The %1 model has %2 computed solutes\n"
475  " and an RMSD of %3" )
476  .arg( sctype ).arg( ncsols ).arg( mrec.rmsd ) );
477 
478  set_fittings( mrecs );
479 DbgLv(1) << "post-set-fittings mr0 rmsd" << mrecs[0].rmsd;
480 
481  bfm_new = true;
482  mrs_new = true;
483  mc_done = false;
484  pb_accept->setEnabled( true );
485 }
486 
487 // Slot to store a model records list to disk
489 {
490 DbgLv(1) << "store_mrecs";
491  // Test and return immediately if valid mrecs still required
492  if ( mrecs_required( "Store Model Records" ) )
493  return;
494 
495  // Query and get the file for storing
496  QString store_file = store_dir + "/pcsa-mrs-new_mrecs.xml";
497  store_file = QFileDialog::getSaveFileName( this,
498  tr( "Specify XML File Name for Model Records Store" ), store_dir,
499  tr( "Model Records files (*pcsa-mrs-*.xml);;"
500  "Any XML files (*.xml);;Any files (*)" ) );
501 
502  if ( store_file.isEmpty() )
503  {
504 DbgLv(1) << "store_mrecs - FILE NAME EMPTY";
505  return;
506  }
507 else DbgLv(1) << "store_mrecs - FILE NAME *NOT* EMPTY" << store_file;
508 
509  store_file = store_file.replace( "\\", "/" );
510  QString fdir = store_file.section( "/", 0, -2 ) + "/";
511  QString fname = store_file.section( "/", -1, -1 );
512 
513  // Massage the name to be in "mrs_<name>.xml" form
514  if ( store_file.endsWith( "." ) )
515  { // Ends with ".": no ".xml" is to be added
516  store_file = store_file.left( store_file.length() - 1 );
517  fname = fname .left( fname .length() - 1 );
518  }
519 
520  else if ( ! store_file.endsWith( ".xml" ) )
521  { // If no ".xml" extension, add one
522  store_file = store_file + ".xml";
523  fname = fname + ".xml";
524  }
525 
526  if ( fname.startsWith( "." ) )
527  { // Starts with ".": no "pcsa-mrs-" prefix is to be added
528  store_file = fdir + fname.mid( 1 );
529  }
530 
531  else if ( ! fname.startsWith( "pcsa-mrs-" ) )
532  { // If no "pcsa-mrs-" prefix, add one
533  store_file = fdir + "pcsa-mrs-" + fname;
534  }
535 
536  // Open the specified output file
537  QFile fileo( store_file );
538 
539  if ( !fileo.open( QIODevice::WriteOnly | QIODevice::Text ) )
540  {
541  QMessageBox::critical( this, tr( "Open Error" ),
542  tr( "Cannot open file %1 ." ).arg( store_file ) );
543  return;
544  }
545 
546  // Write out the XML file
547  ctype = mrecs[ 0 ].v_ctype;
548  double xmin = mrecs[ 0 ].xmin;
549  double xmax = mrecs[ 0 ].xmax;
550  double ymin = mrecs[ 0 ].ymin;
551  double ymax = mrecs[ 0 ].ymax;
552  int stype = mrecs[ 0 ].stype;
553  QXmlStreamWriter xmlo( &fileo );
554  QString mrdesc;
555 
556  US_ModelRecord::write_modelrecs( xmlo, mrecs, mrdesc,
557  ctype, xmin, xmax, ymin, ymax, stype );
558  fileo.close();
559 
560  // Report on saved file
561  fdir = store_file.section( "/", 0, -2 ) + "/";
562  fname = store_file.section( "/", -1, -1 );
563  stat_mrecs(
564  tr( "Model Records have been stored in file\n"
565  " \"%1\", of directory\n \"%2\"." )
566  .arg( fname ).arg( fdir), true );
567 }
568 
569 // Slot to load a best final model from disk
571 {
572 DbgLv(1) << "load_bfm";
573 //under_construct( "Load Final Model" );
574  // Test and return immediately if valid mrecs still required
575  if ( mrecs_required( "Load Final Model" ) )
576  return;
577 
578  // Query and get the file for loading
579  QString load_file = store_dir + "/pcsa-bfm-old_mrecs.xml";
580  load_file = QFileDialog::getOpenFileName( this,
581  tr( "Select XML File Name for Best Final Model Load" ), store_dir,
582  tr( "Best Final Model files (*pcsa-bfm-*.xml);;"
583  "Any XML files (*.xml);;Any files (*)" ) );
584 
585  if ( load_file.isEmpty() )
586  {
587  return;
588  }
589 
590  load_file = load_file.replace( "\\", "/" );
591  QString fdir = load_file.section( "/", 0, -2 ) + "/";
592  QString fname = load_file.section( "/", -1, -1 );
593 
594  // Open the specified input file
595  QFile filei( load_file );
596 
597  if ( !filei.open( QIODevice::ReadOnly ) )
598  {
599  QMessageBox::critical( this, tr( "Open Error" ),
600  tr( "Cannot open file %1 ." ).arg( load_file ) );
601  return;
602  }
603 
604  // Read in and parse the XML file to generate a new BFM
605  int nisols = 0;
606  bool is_bfmf = false;
607  QString xmlname = "";
608  QXmlStreamReader xmli( &filei );
609 
610  while ( ! xmli.atEnd() )
611  {
612  xmli.readNext();
613 
614  if ( xmli.isComment() )
615  { // Verify DOCTYPE PcsaBestFinalModel
616  QString comm = xmli.text().toString();
617 //DbgLv(1) << "LM:xml: comm" << comm;
618 
619  if ( comm.contains( "PcsaBestFinalModel" ) )
620  is_bfmf = true;
621 
622  else
623  {
624  QMessageBox::critical( this, tr( "File Type Error" ),
625  tr( "File \"%1\" is not a PcsaBestFinalModel XML file." )
626  .arg( fname ) );
627  filei.close();
628  return;
629  }
630  }
631 
632  xmlname = xmli.name().toString();
633 
634  if ( xmli.isStartElement() )
635  {
636 //DbgLv(1) << "LM:xml: start name" << xmlname;
637  QXmlStreamAttributes xattrs = xmli.attributes();
638 
639  if ( xmlname == "modelrecord" )
640  {
641  nisols = xattrs.value( "curve_points" )
642  .toString().toInt();
643  mrec.taskx = xattrs.value( "taskx" ).toString().toInt();
644  mrec.str_y = xattrs.value( "start_y" ).toString().toDouble();
645  mrec.end_y = xattrs.value( "end_y" ).toString().toDouble();
646  mrec.par1 = xattrs.value( "par1" ).toString().toDouble();
647  mrec.par2 = xattrs.value( "par2" ).toString().toDouble();
648  mrec.par3 = xattrs.value( "par3" ).toString().toDouble();
649  mrec.rmsd = xattrs.value( "rmsd" ).toString().toDouble();
650  mrec.ctype = xattrs.value( "type" ).toString().toInt();
651  mrec.xmin = xattrs.value( "xmin" ).toString().toDouble();
652  mrec.xmax = xattrs.value( "xmax" ).toString().toDouble();
653  mrec.ymin = xattrs.value( "ymin" ).toString().toDouble();
654  mrec.ymax = xattrs.value( "ymax" ).toString().toDouble();
655  mrec.isolutes.resize( nisols );
656  mrec.csolutes.clear();
657  ncsols = 0;
658 //DbgLv(1) << "LM:xml: nmrecs" << nmrecs << "kisols" << kisols;
659  }
660 
661  else if ( xmlname == "c_solute" )
662  {
663  US_ZSolute csolute;
664  csolute.x = xattrs.value( "x" ).toString().toDouble();
665  csolute.y = xattrs.value( "y" ).toString().toDouble();
666  csolute.z = xattrs.value( "z" ).toString().toDouble();
667  csolute.c = xattrs.value( "c" ).toString().toDouble();
668  csolute.x *= 1.e-13;
669 
670  mrec.csolutes << csolute;
671  ncsols++;
672  }
673  }
674  }
675 DbgLv(1) << "LM:xml: End ALL: nmrecs" << nmrecs << "last ncsols" << ncsols;
676  filei.close();
677 
678  if ( xmli.hasError() )
679  {
680  QMessageBox::critical( this, tr( "XML Invalid" ),
681  tr( "File \"%1\" is not a valid XML file." ).arg( fname ) );
682  return;
683  }
684 
685  else if ( ! is_bfmf )
686  {
687  QMessageBox::critical( this, tr( "File Type Error" ),
688  tr( "File \"%1\" is not a PcsaBestFinalModel XML file." )
689  .arg( fname ) );
690  return;
691  }
692 
693  // Test if new final model is compatible with model records
694  if ( bfm_incompat( fname ) )
695  return;
696 
697  // Re-generate curve points for the model
698  curve_isolutes( mrec );
699 
700  QString sctype = US_ModelRecord::ctype_text( mrec.ctype );
701 
702  // Build the model that goes along with the BFM
703  bfm_model();
704 
705  // Report on loaded file
706  stat_bfm(
707  tr( "A new Best Final Model has been loaded from file\n"
708  " \"%1\", of directory\n \"%2\".\n"
709  "The %3 model has %4 computed solutes\n"
710  " and an RMSD of %5" )
711  .arg( fname ).arg( fdir).arg( sctype ).arg( ncsols ).arg( mrec.rmsd ) );
712 
713 
714  bfm_new = true;
715  mc_done = false;
716  mrecs[ 0 ] = mrec;
717  set_fittings( mrecs );
718  pb_accept->setEnabled( true );
719 }
720 
721 // Slot to store a best final model to disk
723 {
724 DbgLv(1) << "store_bfm";
725  // Query and get the file for storing
726  QString store_file = store_dir + "/pcsa-bfm-new_bfm.xml";
727  store_file = QFileDialog::getSaveFileName( this,
728  tr( "Specify XML File Name for Best Final Model Store" ), store_dir,
729  tr( "Best Final Model files (*pcsa-bfm-*.xml);;"
730  "Any XML files (*.xml);;Any files (*)" ) );
731 
732  if ( store_file.isEmpty() )
733  {
734  return;
735  }
736 
737  store_file = store_file.replace( "\\", "/" );
738  QString fdir = store_file.section( "/", 0, -2 ) + "/";
739  QString fname = store_file.section( "/", -1, -1 );
740 
741  // Massage the name to be in "pcsa-bfm-<name>.xml" form
742  if ( store_file.endsWith( "." ) )
743  { // Ends with ".": no ".xml" is to be added
744  store_file = store_file.left( store_file.length() - 1 );
745  fname = fname .left( fname .length() - 1 );
746  }
747 
748  else if ( ! store_file.endsWith( ".xml" ) )
749  { // If no ".xml" extension, add one
750  store_file = store_file + ".xml";
751  fname = fname + ".xml";
752  }
753 
754  if ( fname.startsWith( "." ) )
755  { // Starts with ".": no "pcsa-bfm-" prefix is to be added
756  store_file = fdir + fname.mid( 1 );
757  }
758 
759  else if ( ! fname.startsWith( "pcsa-bfm-" ) )
760  { // If no "pcsa-bfm-" prefix, add one
761  store_file = fdir + "pcsa-bfm-" + fname;
762  }
763 
764  // Open the specified output file
765  QFile fileo( store_file );
766 
767  if ( !fileo.open( QIODevice::WriteOnly | QIODevice::Text ) )
768  {
769  QMessageBox::critical( this, tr( "Open Error" ),
770  tr( "Cannot open file %1 ." ).arg( store_file ) );
771  return;
772  }
773 
774  // Write out the XML file
775  ctype = mrec.ctype;
776 // int nisols = (int)le_crpoints->value();
777  int kisols = mrec.isolutes.size();
778  int ncsols = mrec.csolutes.size();
779  double xmin = mrec.xmin;
780  double xmax = mrec.xmax;
781  double ymin = mrec.ymin;
782  double ymax = mrec.ymax;
783  QXmlStreamWriter xmlo;
784  xmlo.setDevice( &fileo );
785  xmlo.setAutoFormatting( true );
786  xmlo.writeStartDocument( "1.0" );
787  xmlo.writeComment( "DOCTYPE PcsaBestFinalModel" );
788  xmlo.writeCharacters( "\n" );
789  xmlo.writeStartElement( "modelrecord" );
790  xmlo.writeAttribute( "version", "1.0" );
791  xmlo.writeAttribute( "type", QString::number( ctype ) );
792  xmlo.writeAttribute( "xmin", QString::number( xmin ) );
793  xmlo.writeAttribute( "xmax", QString::number( xmax ) );
794  xmlo.writeAttribute( "ymin", QString::number( ymin ) );
795  xmlo.writeAttribute( "ymax", QString::number( ymax ) );
796  xmlo.writeAttribute( "curve_points", QString::number( kisols ) );
797  xmlo.writeAttribute( "taskx", QString::number( mrec.taskx ) );
798  xmlo.writeAttribute( "start_y", QString::number( mrec.str_y ) );
799  xmlo.writeAttribute( "end_y", QString::number( mrec.end_y ) );
800  xmlo.writeAttribute( "par1", QString::number( mrec.par1 ) );
801  xmlo.writeAttribute( "par2", QString::number( mrec.par2 ) );
802  xmlo.writeAttribute( "par3", QString::number( mrec.par3 ) );
803  xmlo.writeAttribute( "rmsd", QString::number( mrec.rmsd ) );
804 
805  for ( int cc = 0; cc < ncsols; cc++ )
806  {
807  xmlo.writeStartElement( "c_solute" );
808  double sval = mrec.csolutes[ cc ].x * 1.e13;
809  xmlo.writeAttribute( "x", QString::number( sval ) );
810  xmlo.writeAttribute( "y", QString::number( mrec.csolutes[ cc ].y ) );
811  xmlo.writeAttribute( "z", QString::number( mrec.csolutes[ cc ].z ) );
812  xmlo.writeAttribute( "c", QString::number( mrec.csolutes[ cc ].c ) );
813  xmlo.writeEndElement();
814  }
815 
816  xmlo.writeEndElement();
817  xmlo.writeEndDocument();
818  fileo.close();
819 
820  // Report on the saved file
821  fdir = store_file.section( "/", 0, -2 ) + "/";
822  fname = store_file.section( "/", -1, -1 );
823 
824  stat_bfm(
825  tr( "The Best Final Model has been stored in file\n"
826  " \"%1\", of directory\n \"%2\"." )
827  .arg( fname ).arg( fdir), true );
828 }
829 
830 // Slot to reset the best final model to its initial state
832 {
833 DbgLv(1) << "reset_bfm";
834  mrec = mrec0;
835  mrecs[ 0 ] = mrec0;
836 
837  stat_bfm( tr( "Best Final Model has been reset to original state." ) );
838 
839  if ( bfm0_exists )
840  {
841  set_fittings( mrecs );
842 
843  stat_bfm( tr( "An initial best final model, with RMSD of %1,"
844  " has been restored." ).arg( mrec.rmsd ), true );
845  }
846 
847  else
848  {
849  stat_bfm( tr( "The initial empty best final model\n"
850  " has been restored." ), true );
851  }
852 
853  bfm_new = false;
854  mc_done = false;
855 }
856 
857 // Slot to reset the list of model records to its initial state
859 {
860 DbgLv(1) << "reset_mrecs";
861  mrecs = mrecs0;
862  mrec = mrec0;
863  nmrecs = mrecs.size();
864 
865  stat_mrecs( tr( "Model Records have been reset to original state." ) );
866 
867  if ( mrs0_exists )
868  {
869  stat_mrecs( tr( "An initial model records list, with %1 fits,\n"
870  " has been restored." ).arg( nmrecs ), true );
871  }
872 
873  else
874  { // We are starting with models not yet computed
875  stat_mrecs( tr( "The initial empty model records list\n"
876  " has been restored." ), true );
877  }
878 
879  mrs_new = false;
880  reset_bfm();
881  pb_accept->setEnabled( false );
882 }
883 
884 // Slot to build a new best final model from specified fitting controls
886 {
887 DbgLv(1) << "build_bfm";
888 //under_construct( "Build Final Model" );
889  // Test and return immediately if valid mrecs still required
890  if ( mrecs_required( "Build Final Model" ) )
891  return;
892 
893  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
894  stat_bfm( tr( "A new Best Final Model is being built ..." ) );
895 
896  QString sctype = cb_curvtype->currentText();
897  int ctypex = cb_curvtype->currentIndex();
898  ctype = ( ctypex == 0 ) ? CTYPE_SL : CTYPE_NONE;
899  ctype = ( ctypex == 1 ) ? CTYPE_IS : ctype;
900  ctype = ( ctypex == 2 ) ? CTYPE_DS : ctype;
901  ctype = ( ctypex == 3 ) ? CTYPE_HL : ctype;
902  ctype = ( ctypex == 4 ) ? CTYPE_2O : ctype;
903  double xmin = le_x_lower ->text().toDouble();
904  double xmax = le_x_upper ->text().toDouble();
905  double ymin = le_y_lower ->text().toDouble();
906  double ymax = le_y_upper ->text().toDouble();
907  mrec.ctype = ctype;
908  mrec.xmin = xmin;
909  mrec.xmax = xmax;
910  mrec.ymin = ymin;
911  mrec.ymax = ymax;
912 
913  // Set parameters for the specific curve to use
914  if ( ctype == CTYPE_SL )
915  {
916  mrec.str_y = le_y_strpt ->text().toDouble();
917  mrec.end_y = le_y_endpt ->text().toDouble();
918  mrec.par1 = mrec.str_y;
919  mrec.par2 = ( mrec.str_y - mrec.end_y ) / ( xmax - xmin );
920  }
921  else if ( ctype == CTYPE_IS || ctype == CTYPE_DS )
922  {
923  mrec.str_y = ymin;
924  mrec.end_y = ymax;
925  mrec.par1 = le_sigmpar1->text().toDouble();
926  mrec.par2 = le_sigmpar2->text().toDouble();
927  }
928 
929  else if ( ctype == CTYPE_HL )
930  {
931  mrec.end_y = le_y_endpt ->text().toDouble();
932  mrec.str_y = mrec.end_y;
933  mrec.par1 = mrec.str_y;
934  mrec.par2 = 0.0;
935  }
936 
937  else if ( ctype == CTYPE_2O )
938  {
939  mrec.str_y = ymin;
940  mrec.end_y = ymax;
941  mrec.par1 = le_sigmpar1->text().toDouble();
942  mrec.par2 = le_sigmpar2->text().toDouble();
943  if ( mrecs.size() > 0 )
944  mrec.par3 = mrecs[ 0 ].par3;
945  }
946 
947  // Generate the solute points on the curve
948  curve_isolutes( mrec );
949 
950  // Compute the simulation and computed-solutes
951  QList< US_SolveSim::DataSet* > dsets;
952  dsets << dset0;
953  US_SolveSim::Simulation sim_vals;
954  sim_vals.zsolutes = mrec.isolutes;
955  sim_vals.ti_noise = mrec.ti_noise;
956  sim_vals.ri_noise = mrec.ri_noise;
957 
958  US_SolveSim* solvesim = new US_SolveSim( dsets, 0, false );
959 
960  solvesim->calc_residuals( 0, 1, sim_vals );
961 
962  mrec.variance = sim_vals.variance;
963  mrec.rmsd = sqrt( sim_vals.variance );
964  mrec.csolutes = sim_vals.zsolutes;
965 
966  ncsols = mrec.csolutes.size();
967 
968  // Build the model that goes along with the BFM
969  bfm_model();
970 
971  // Report on built file
972  stat_bfm(
973  tr( "A new Best Final Model has been built\n"
974  " from the specified fitting controls.\n"
975  "The %1 model has %2 computed solutes\n"
976  " and an RMSD of %3" )
977  .arg( sctype ).arg( ncsols ).arg( mrec.rmsd ), true );
978 
979  stat_mrecs(
980  tr( "A new best final %1-solute model ( RMSD = %2 )\n"
981  " now occupies the top curve model records list spot." )
982  .arg( ncsols ).arg( mrec.rmsd ), true );
983 
984  mrecs[ 0 ] = mrec;
985  bfm_new = true;
986  mrs_new = true;
987  mc_done = false;
988  QApplication::restoreOverrideCursor();
989  qApp->processEvents();
990  pb_accept->setEnabled( true );
991 }
992 
993 // Slot to start and process monte carlo iterations
995 {
996  // Test and return immediately if valid mrecs still required
997  if ( mrecs_required( "Start Monte Carlo" ) )
998  return;
999 
1000 DbgLv(1) << "start_montecarlo";
1001  wdata = dset0->run_data;
1002  edata = &wdata;
1003  mciters = le_mciters->text().toInt();
1004  stat_bfm( tr( "%1 Monte Carlo iterations are being computed..." )
1005  .arg( mciters ) );
1006  ksiters = 0;
1007  kciters = 0;
1008  int nsol_m = mrec.isolutes.size();
1009  double par1_m = mrec.par1;
1010  double par2_m = mrec.par2;
1011  double ymin_m = mrec.ymin;
1012  double ymax_m = mrec.ymax;
1013  int nsol_p = le_crpoints->text().toInt();
1014  double par1_p = le_sigmpar1->text().toDouble();
1015  double par2_p = le_sigmpar2->text().toDouble();
1016  double ymin_p = le_y_lower ->text().toDouble();
1017  double ymax_p = le_y_upper ->text().toDouble();
1018  double difp1 = qAbs( ( par1_m - par1_p ) / par1_m );
1019  double difp2 = qAbs( ( par2_m - par2_p ) / par2_m );
1020  double dymin = qAbs( ( ymin_m - ymin_p ) / ymin_m );
1021  double dymax = qAbs( ( ymax_m - ymax_p ) / ymax_m );
1022 
1023  if ( nsol_p != nsol_m || difp1 > 1.0e-4 || difp2 > 1.0e-4 ||
1024  dymin > 1.0e-4 || dymin > 1.0e-4 )
1025  {
1026  mrec.isolutes.resize( nsol_p );
1027  mrec.par1 = par1_p;
1028  mrec.par2 = par2_p;
1029  mrec.ymin = ymin_p;
1030  mrec.ymax = ymax_p;
1031 DbgLv(1) << " MC reset curves: p1_m p2_m p1_p p2_p ns_m ns_p"
1032  << par1_m << par2_m << par1_p << par2_p << nsol_m << nsol_p;
1033 DbgLv(1) << " MC reset curves: dp1 dp2 sdp1 sdp2"
1034  << difp1 << difp2 << (par1_m-par1_p) << (par2_m-par2_p);
1035 DbgLv(1) << " MC reset curves: dyl dyh sdyl sdyh"
1036  << dymin << dymax << (ymin_m-ymin_p) << (ymax_m-ymax_p);
1037 
1038  curve_isolutes( mrec );
1039  }
1040 
1041  mrecs_mc.clear();
1042  US_ModelRecord mrec_mc = mrec;
1043  US_SolveSim::DataSet dset = *dset0;
1044  QList< US_SolveSim::DataSet* > dsets;
1045  dsets << &dset;
1046 
1047  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1048  b_progress->reset();
1049  b_progress->setMaximum( mciters );
1050 
1051  if ( nthr == 1 )
1052  { // Monte Carlo with single thread
1053  for ( int iter = 0; iter < mciters; iter++ )
1054  {
1055  ksiters++;
1056  US_SolveSim::Simulation sim_vals;
1057  sim_vals.zsolutes = mrec.isolutes;
1058  dsets[ 0 ]->run_data = wdata;
1059 
1060  US_SolveSim* solvesim = new US_SolveSim( dsets, 0, false );
1061 
1062  solvesim->calc_residuals( 0, 1, sim_vals );
1063 
1064  kciters = ksiters;
1065  mrec_mc.variance = sim_vals.variance;
1066  mrec_mc.rmsd = sqrt( sim_vals.variance );
1067  mrec_mc.csolutes = sim_vals.zsolutes;
1068  ncsols = mrec_mc.csolutes.size();
1069 DbgLv(1) << " kciters" << kciters << "rmsd" << mrec_mc.rmsd
1070  << "ncsols" << ncsols;
1071 
1072  mrecs_mc << mrec_mc;
1073 
1074  // Set up new data modified by a gaussian distribution
1075  if ( iter == 0 )
1076  {
1077  set_gaussians( sim_vals );
1078  }
1079 
1080  // Except on last iteration, we must create new "experiment" data
1081  if ( kciters < mciters )
1082  {
1083  apply_gaussians();
1084  }
1085 
1086  stat_bfm(
1087  tr( "%1 are completed ( last: %2-solute, RMSD=%3 )" )
1088  .arg( kciters ).arg( ncsols ).arg( mrec_mc.rmsd ), true, 1 );
1089  b_progress->setValue( kciters );
1090  qApp->processEvents();
1091  }
1092 
1093  // Complete the MonteCarlo process
1094  b_progress->setValue( mciters );
1095  qApp->processEvents();
1096 
1097  montecarlo_done();
1098 
1099  QApplication::restoreOverrideCursor();
1100  qApp->processEvents();
1101  }
1102 
1103  else
1104  { // Monte Carlo in threads
1105  stat_bfm(
1106  tr( "%1 Monte Carlo iterations are being"
1107  " computed in %2 threads..." ).arg( mciters ).arg( nthr ) );
1108 
1109  // Do the first iteration computation and set gaussians
1110  US_SolveSim::Simulation sim_vals;
1111  sim_vals.zsolutes = mrec.isolutes;
1112  dsets[ 0 ]->run_data = wdata;
1113  ksiters++;
1114 
1115  US_SolveSim* solvesim = new US_SolveSim( dsets, 0, false );
1116 
1117  solvesim->calc_residuals( 0, 1, sim_vals );
1118 
1119  kciters = ksiters;
1120  mrec_mc.variance = sim_vals.variance;
1121  mrec_mc.rmsd = sqrt( sim_vals.variance );
1122  mrec_mc.csolutes = sim_vals.zsolutes;
1123  ncsols = mrec_mc.csolutes.size();
1124 DbgLv(1) << " kciters" << kciters << "rmsd" << mrec_mc.rmsd
1125  << "ncsols" << ncsols << "res tskx,thrn" << 1 << 0;
1126  stat_bfm(
1127  tr( "%1 are completed ( last: %2-solute, RMSD=%3 )" )
1128  .arg( kciters ).arg( ncsols ).arg( mrec_mc.rmsd ), true, 1 );
1129  b_progress->setValue( kciters );
1130  qApp->processEvents();
1131 
1132  mrecs_mc << mrec_mc;
1133  set_gaussians( sim_vals );
1134 
1135  WorkPacketPc wtbase;
1136  wtbase.par1 = mrec.par1;
1137  wtbase.par2 = mrec.par2;
1138  wtbase.str_y = mrec.str_y;
1139  wtbase.end_y = mrec.end_y;
1140  wtbase.isolutes = mrec.isolutes;
1141  wtbase.csolutes.clear();
1142  wtbase.noisf = 0;
1143  wtbase.dsets = dsets;
1144  wtbase.depth = 0;
1145  US_SolveSim::DataSet wkdset = *(dsets[ 0 ]);
1146  wkdsets.clear();
1147 
1148  for ( int jt = 0; jt < nthr; jt++ )
1149  { // Build up a list of datasets for each thread
1150  wkdsets << wkdset;
1151  }
1152 
1153  // Start the next few iterations in available threads
1154  for ( int jt = 0; jt < nthr; jt++ )
1155  {
1156  apply_gaussians();
1157 
1158  WorkPacketPc wtask = wtbase;
1159  US_SolveSim::Simulation sim_vals;
1160  sim_vals.zsolutes = mrec.isolutes;
1161 
1162  wtask.thrn = jt + 1;
1163  wtask.taskx = jt + 1;
1164  wtask.str_y = mrec.str_y;
1165  wtask.end_y = mrec.end_y;
1166  wtask.sim_vals = sim_vals;
1167  wtask.dsets[ 0 ] = &wkdsets[ jt ];
1168 
1169  wtask.dsets[ 0 ]->run_data = wdata;
1170 
1171  WorkerThreadPc* wthrd = new WorkerThreadPc( this );
1172  connect( wthrd, SIGNAL( work_complete( WorkerThreadPc* ) ),
1173  this, SLOT ( process_job ( WorkerThreadPc* ) ) );
1174 
1175  wthrd->define_work( wtask );
1176 
1177  wthrd->start();
1178 
1179  ksiters++;
1180 DbgLv(1) << " ksiters" << ksiters << "dsets[0]" << wtask.dsets[0];
1181  }
1182 
1183  }
1184 
1185 }
1186 
1187 // Set gaussian distribution: sigmas and iteration 1 simulation data
1189 {
1190  bool gausmoo = US_Settings::debug_match( "MC-GaussianSmooth" );
1191  int nscans = edata->scanCount();
1192  int npoints = edata->pointCount();
1193 DbgLv(1) << "AA: set_gaus: gausmoo" << gausmoo;
1194  US_DataIO::RawData* sdata = &sim_vals.sim_data;
1195  US_DataIO::RawData* rdata = &sim_vals.residuals;
1196 
1197  sigmas.clear();
1198 
1199  for ( int ss = 0; ss < nscans; ss++ )
1200  { // Loop to accumulate the residuals from iteration 1
1201  QVector< double > vv( npoints );
1202 
1203  for ( int rr = 0; rr < npoints; rr++ )
1204  { // Get all residuals points from a scan
1205  vv[ rr ] = qAbs( rdata->value( ss, rr ) );
1206  }
1207 
1208  if ( gausmoo )
1209  { // Do a 5-point gaussian smooth of each scan's residuals
1211  }
1212 
1213  // Append residuals to build total sigmas array
1214  sigmas << vv;
1215  }
1216 
1217  if ( gausmoo )
1218  { // Scale the sigmas so they are at the same level as original residuals
1219  double rmsdi = mrecs_mc[ 0 ].rmsd;
1220  double rmsds = 0.0;
1221  int ntpoints = nscans * npoints;
1222 
1223  for ( int rr = 0; rr < ntpoints; rr++ )
1224  rmsds += sq( sigmas[ rr ] ); // Sum of squares
1225 
1226  rmsds = sqrt( rmsds / (double)ntpoints ); // Sigmas RMSD
1227  double sigscl = rmsdi / rmsds; // Sigma scale factor
1228 
1229  for ( int rr = 0; rr < ntpoints; rr++ )
1230  sigmas[ rr ] *= sigscl; // Scaled sigmas
1231 DbgLv(1) << "AA: gausmoo: rmsd-i rmsc-s sigscl" << rmsdi << rmsds << sigscl;
1232  }
1233 
1234  // Save the simulation data set from iteration 1
1235  sdata1 = *sdata;
1236 }
1237 
1238 // Apply gaussians: add in random variations of sigmas to base simulation
1240 {
1241  int nscans = edata->scanCount();
1242  int npoints = edata->pointCount();
1243  int kk = 0;
1244 
1245  // Add box-muller portion of each sigma to the base simulation
1246  for ( int ss = 0; ss < nscans; ss++ )
1247  {
1248  for ( int rr = 0; rr < npoints; rr++ )
1249  {
1250  double svari = US_Math2::box_muller( 0.0, sigmas[ kk++ ] );
1251  wdata.setValue( ss, rr, ( sdata1.value( ss, rr ) + svari ) );
1252  }
1253  }
1254 }
1255 
1256 // Process the completion of an MC worker thread
1258 {
1259  kciters++;
1260  WorkPacketPc wresult;
1261  wthr->get_result( wresult );
1262 
1263  US_ModelRecord mrec_mc = mrecs_mc[ 0 ];
1264  mrec_mc.variance = wresult.sim_vals.variance;
1265  mrec_mc.rmsd = sqrt( mrec_mc.variance );
1266  mrec_mc.csolutes = wresult.sim_vals.zsolutes;
1267  ncsols = mrec_mc.csolutes.size();
1268 DbgLv(1) << " kciters" << kciters << "rmsd" << mrec_mc.rmsd
1269  << "ncsols" << ncsols << "res tskx,thrn" << wresult.taskx << wresult.thrn;
1270 
1271  stat_bfm(
1272  tr( "%1 are completed ( last: %2-solute, RMSD=%3 )" )
1273  .arg( kciters ).arg( ncsols ).arg( mrec_mc.rmsd ), true, 1 );
1274  b_progress->setValue( kciters );
1275  qApp->processEvents();
1276 
1277  mrecs_mc << mrec_mc;
1278 
1279  if ( kciters == mciters )
1280  { // Complete the MonteCarlo process
1281  b_progress->setValue( mciters );
1282 
1283  montecarlo_done();
1284 
1285  QApplication::restoreOverrideCursor();
1286  qApp->processEvents();
1287  }
1288 
1289  else if ( ksiters < mciters )
1290  { // Submit a new task
1291  ksiters++;
1292 DbgLv(1) << " ksiters" << ksiters << " apply_gaussians";
1293 
1294  apply_gaussians();
1295 
1296  WorkPacketPc wtask = wresult;
1297  wtask.dsets[ 0 ] = &wkdsets[ wresult.thrn - 1 ];
1298  wtask.dsets[ 0 ]->run_data = wdata;
1299  wtask.taskx = ksiters;
1300 DbgLv(1) << " ksiters" << ksiters << " wt tskx,thrn"
1301  << wtask.taskx << wtask.thrn;
1302 
1303  delete wthr;
1304 
1305  WorkerThreadPc* wthrd = new WorkerThreadPc( this );
1306  connect( wthrd, SIGNAL( work_complete( WorkerThreadPc* ) ),
1307  this, SLOT ( process_job ( WorkerThreadPc* ) ) );
1308 
1309  wthrd->define_work( wtask );
1310  wthrd->start();
1311 DbgLv(1) << " ksiters" << ksiters << " dsets[0]" << wtask.dsets[0];
1312  }
1313 }
1314 
1315 // Complete model records and the final model after monte carlo completion
1317 {
1318 DbgLv(1) << "==montecarlo_done()==";
1319  stat_bfm( tr( "Building MC models and final composite..." ), true );
1320 #if 0
1321  int nccsol = 0;
1322  QVector< US_ZSolute > compsols;
1323  QStringList sortlst;
1324 #endif
1325 #if 1
1326  QStringList mfnames;
1327  edata = &dset0->run_data;
1328  int ctype = mrecs_mc[ 0 ].ctype;
1329  int stype = mrecs_mc[ 0 ].stype;
1330  QString tmppath = US_Settings::tmpDir() + "/";
1331  QString runID = edata->runID;
1332  QString tripID = edata->cell + edata->channel + edata->wavelength;
1333  QString dates = "e" + edata->editID + "_a"
1334  + QDateTime::currentDateTime().toUTC()
1335  .toString( "yyMMddhhmm" );
1336  QString analysType = "PCSA-SL-MC";
1337  analysType = ( ctype == CTYPE_IS ) ? "PCSA-IS-MC" : analysType;
1338  analysType = ( ctype == CTYPE_DS ) ? "PCSA-DS-MC" : analysType;
1339  analysType = ( ctype == CTYPE_HL ) ? "PCSA-HL-MC" : analysType;
1340  analysType = ( ctype == CTYPE_2O ) ? "PCSA-2O-MC" : analysType;
1341  QString analysID = dates + "_" + analysType + "_local_";
1342  QString base_mdesc = runID + "." + tripID + "." + analysID;
1344  model.monteCarlo = true;
1345 #endif
1346  US_Model::SimulationComponent zcomponent;
1347  zcomponent.vbar20 = dset0->vbar20;
1348 
1349  // Build individual models and append all solutes to one composite
1350  for ( int jmc = 0; jmc < mciters; jmc++ )
1351  {
1352  mrec = mrecs_mc[ jmc ];
1353  QVector< US_ZSolute > csolutes = mrec.csolutes;
1354  int nsols = csolutes.size();
1355  model.components.resize( nsols );
1356 
1357  for ( int cc = 0; cc < nsols; cc++ )
1358  {
1359  // Get component values and sorting string
1360 #if 0
1361  double sol_x = csolutes[ cc ].x;
1362  double sol_y = csolutes[ cc ].y;
1363  double sol_z = csolutes[ cc ].z;
1364  double sol_c = csolutes[ cc ].c;
1365  QString sol_id = QString().sprintf( "%.4f:%.4f:%d",
1366  sol_x * 1.e13, sol_y, nccsol++ );
1367 DbgLv(1) << "MCD: cc" << cc << "sol_id" << sol_id;
1368 
1369  // Save unsorted/summed solute and sorting string
1370  US_ZSolute compsol;
1371  compsol.x = sol_x;
1372  compsol.y = sol_y;
1373  compsol.z = sol_z;
1374  compsol.c = sol_c;
1375  compsols << compsol;
1376  sortlst << sol_id;
1377 
1378  // Build the model component
1379  model.components[ cc ] = zcomponent;
1380  model.components[ cc ].s = sol_x;
1381  model.components[ cc ].f_f0 = sol_y;
1382  model.components[ cc ].vbar20 = sol_z;
1383  model.components[ cc ].signal_concentration = sol_c;
1384  model.components[ cc ].name = QString().sprintf( "SC%04d", cc + 1 );
1385 #endif
1386 #if 1
1387  model.components[ cc ] = zcomponent;
1388  US_ZSolute::set_mcomp_values( model.components[ cc ], csolutes[ cc ],
1389  stype, true );
1390 #endif
1392  }
1393 
1394  // Save the individual MC model
1395  mrec.model = model;
1396  mrecs_mc[ jmc ] = mrec;
1397 
1398  // Write the iteration model to a temp file and save its name
1399  QString iterID = QString().sprintf( "mc%04d", jmc + 1 );
1400  model.description = base_mdesc + iterID + ".model";
1401  QString mfname = tmppath + model.description + ".tmp";
1402  mfnames << mfname;
1403  model.write( mfname );
1404  }
1405 
1406  // Now sort the solute id strings to create sorted composite
1407 #if 0
1408  qSort( sortlst );
1409  US_ZSolute pcompsol;
1410  US_ZSolute ccompsol;
1411  QString pskmatch = QString();
1412  mrec.csolutes.clear();
1413  double cnorm = 1.0 / (double)mciters;
1414  ncsols = 0;
1415 
1416  for ( int cc = 0; cc < nccsol; cc++ )
1417  {
1418  QString sol_id = sortlst[ cc ];
1419  QString skmatch = sol_id.section( ":", 0, 1 );
1420  int ccin = sol_id.section( ":", 2, 2 ).toInt();
1421  ccompsol = compsols[ ccin ];
1422 
1423  if ( skmatch != pskmatch )
1424  { // New s,k combination: output previous component, start new sum
1425  if ( cc > 0 )
1426  {
1427  pcompsol.c *= cnorm;
1428  mrec.csolutes << pcompsol;
1429  ncsols++;
1430  }
1431 
1432  pcompsol = ccompsol;
1433  pskmatch = skmatch;
1434 DbgLv(1) << "MCD: cc ccin ncsols" << cc << ccin << ncsols;
1435  }
1436 
1437  else
1438  { // Identical s,k to previous: sum concentration;
1439  pcompsol.c += ccompsol.c;
1440  }
1441  }
1442 
1443  // Output last component
1444  pcompsol.c *= cnorm;
1445  mrec.csolutes << pcompsol;
1446  ncsols++;
1447  US_Model modela;
1448 
1449  model = mrec.model; // Model to pass back to main
1450  model.components.resize( ncsols );
1451  modela = model; // Model for application (corrected)
1452  double sfactor = 1.0 / dset0->s20w_correction;
1453  double dfactor = 1.0 / dset0->D20w_correction;
1454 
1455  // Build the model that goes along with the new composite model record
1456  for ( int cc = 0; cc < ncsols; cc++ )
1457  {
1458  model.components[ cc ] = zcomponent;
1459  model.components[ cc ].s = mrec.csolutes[ cc ].x;
1460  model.components[ cc ].f_f0 = mrec.csolutes[ cc ].y;
1461  model.components[ cc ].vbar20 = mrec.csolutes[ cc ].z;
1462  model.components[ cc ].signal_concentration = mrec.csolutes[ cc ].c;
1463  model.components[ cc ].name = QString().sprintf( "SC%04d", cc + 1 );
1465 
1466  modela.components[ cc ] = model.components[ cc ];
1467  modela.components[ cc ].s *= sfactor;
1468  modela.components[ cc ].D *= dfactor;
1469  }
1470 #endif
1471 #if 1
1472  // Create composite MC file and load the model
1473  QString cmfname = US_Model::composite_mc_file( mfnames, true );
1474  model.load( cmfname );
1475  US_Model modela = model; // Model for application (corrected)
1476  ncsols = model.components.size();
1477  double sfactor = 1.0 / dset0->s20w_correction;
1478  double dfactor = 1.0 / dset0->D20w_correction;
1479 
1480  // Build the apply-model that goes along with the new composite model record
1481  for ( int cc = 0; cc < ncsols; cc++ )
1482  {
1483  modela.components[ cc ].s *= sfactor;
1484  modela.components[ cc ].D *= dfactor;
1485  }
1486 #endif
1487 
1488  // Do a fit with the composite model and get the RMSD
1489  US_DataIO::RawData* sdata = &mrec.sim_data;
1490  US_AstfemMath::initSimData( *sdata, *edata, 0.0 );
1491 
1492  US_Astfem_RSA astfem_rsa( modela, dset0->simparams );
1493  astfem_rsa.calculate( *sdata );
1494 
1495  int nscans = edata->scanCount();
1496  int npoints = edata->pointCount();
1497  double varia = 0.0;
1498  bool have_ti = ( mrec.ti_noise.size() > 0 );
1499  bool have_ri = ( mrec.ri_noise.size() > 0 );
1500  double tinoi = 0.0;
1501  double rinoi = 0.0;
1502 
1503  for ( int ss = 0; ss < nscans; ss++ )
1504  {
1505  rinoi = have_ri ? mrec.ri_noise[ ss ] : 0.0;
1506 
1507  for ( int rr = 0; rr < npoints; rr++ )
1508  {
1509  tinoi = have_ti ? mrec.ti_noise[ rr ] : 0.0;
1510  varia += sq( ( edata->value( ss, rr ) - sdata->value( ss, rr )
1511  - rinoi - tinoi ) );
1512  }
1513  }
1514 
1515  varia /= (double)( nscans * npoints );
1516  mrec.variance = varia;
1517  mrec.rmsd = sqrt( varia );
1518  mrec.model = model;
1519  mrecs[ 0 ] = mrec;
1520 
1521  // Report MC completion status
1522  stat_bfm(
1523  tr( "MC models and final %1-solute composite model are built." )
1524  .arg( ncsols ), true );
1525 
1526  stat_mrecs(
1527  tr( "A new best final %1-solute model ( RMSD = %2 )\n"
1528  " now occupies the top curve model records list spot." )
1529  .arg( ncsols ).arg( mrec.rmsd ), true );
1530 
1531  bfm_new = true;
1532  mrs_new = true;
1533  mc_done = true;
1534  pb_accept->setEnabled( true );
1535 }
1536 
1537 // Pop up an under-construction message dialog
1539 {
1540  QMessageBox::information( this, tr( "UNDER CONSTRUCTION" ),
1541  tr( "Implementation of <b>%1</b> is not yet complete." ).arg( proc ) );
1542 }
1543 
1544 // Re-generate the input solute curve points for a model record
1546 {
1547  int nisols = mrec.isolutes.size();
1548  int ctype = mrec.ctype;
1549  int stype = mrec.stype;
1550  int attr_x = ( stype >> 6 ) & 7;
1551  int attr_y = ( stype >> 3 ) & 7;
1552  double xscl = ( attr_x == US_ZSolute::ATTR_S ) ? 1.0e-13 : 1.0;
1553  double yscl = ( attr_y == US_ZSolute::ATTR_S ) ? 1.0e-13 : 1.0;
1554  double xmin = mrec.xmin;
1555  double xmax = mrec.xmax;
1556  double ymin = mrec.ymin;
1557  double ymax = mrec.ymax;
1558  double prng = (double)( nisols - 1 );
1559  double xrng = xmax - xmin;
1560  double xinc = xrng / prng;
1561  double par1 = mrec.par1;
1562  double par2 = mrec.par2;
1563  double xoinc = 1.0 / prng;
1564  double xoff = 0.0;
1565 DbgLv(1) << "AA:CP: xinc" << xinc << "ctype" << ctype;
1566 
1567  if ( ctype == CTYPE_IS ) // Increasing Sigmoid
1568  {
1569  double ydif = ymax - ymin;
1570  double p1rt = sqrt( 2.0 * par1 );
1571 
1572  for ( int kk = 0; kk < nisols; kk++ )
1573  {
1574  double xval = xmin + xoff * xrng;
1575  double efac = 0.5 * erf( ( xoff - par2 ) / p1rt ) + 0.5;
1576  double yval = ymin + ydif * efac;
1577  mrec.isolutes[ kk ].x = xval * xscl;
1578  mrec.isolutes[ kk ].y = yval * yscl;
1579  xoff += xoinc;
1580  }
1581  }
1582 
1583  else if ( ctype == CTYPE_SL ) // Straight Line
1584  {
1585  double yval = mrec.str_y;
1586  double yinc = ( mrec.end_y - mrec.str_y ) / prng;
1587  double xval = xmin;
1588 
1589  for ( int kk = 0; kk < nisols; kk++ )
1590  {
1591  mrec.isolutes[ kk ].x = xval * xscl;
1592  mrec.isolutes[ kk ].y = yval * yscl;
1593  xval += xinc;
1594  yval += yinc;
1595  }
1596 DbgLv(1) << "AA:CP: ni" << nisols << "last yv" << yval;
1597  }
1598 
1599  else if ( ctype == CTYPE_DS ) // Decreasing Sigmoid
1600  {
1601  double ydif = ymin - ymax;
1602  double p1rt = sqrt( 2.0 * par1 );
1603 
1604  for ( int kk = 0; kk < nisols; kk++ )
1605  {
1606  double xval = xmin + xoff * xrng;
1607  double efac = 0.5 * erf( ( xoff - par2 ) / p1rt ) + 0.5;
1608  double yval = ymax + ydif * efac;
1609  mrec.isolutes[ kk ].x = xval * xscl;
1610  mrec.isolutes[ kk ].y = yval * yscl;
1611  xoff += xoinc;
1612  }
1613  }
1614 
1615  else if ( ctype == CTYPE_HL ) // Horizontal Line
1616  {
1617  double yval = mrec.end_y;
1618  double xval = xmin;
1619 
1620  for ( int kk = 0; kk < nisols; kk++ )
1621  {
1622  mrec.isolutes[ kk ].x = xval * xscl;
1623  mrec.isolutes[ kk ].y = yval * yscl;
1624  xval += xinc;
1625  }
1626 DbgLv(1) << "AA:CP: ni" << nisols << "last yv" << yval;
1627  }
1628 
1629  else if ( ctype == CTYPE_2O ) // 2nd-Order Power Law
1630  {
1631  double xval = xmin;
1632  double aval = par1;
1633  double cval = par2;
1634  // y = a * x^b +c
1635  // x^b = ( y - c ) / a
1636  // x = logb( ( y - c ) / a )
1637  // x = log10( ( y - c ) / a ) / log10( b )
1638  // log10( b ) = log10( ( y - c ) / a ) / x
1639  // b = [ ( y - c ) / a ] - log10( x )
1640  //
1641 // double bval = ( ( mrec.end_y - cval ) / qMax( 0.00001, aval ) )
1642 // - log10( xmin );
1643  double bval = ( ( mrec.str_y - cval ) / qMax( 0.00001, aval ) )
1644  - log10( xmin );
1645 
1646  for ( int kk = 0; kk < nisols; kk++ )
1647  {
1648  double yval = aval * pow( xval, bval ) + cval;
1649  mrec.isolutes[ kk ].x = xval * xscl;
1650  mrec.isolutes[ kk ].y = yval * yscl;
1651  xval += xinc;
1652  }
1653  }
1654 DbgLv(1) << "AA:CP: sol0 x,y" << mrec.isolutes[0].x << mrec.isolutes[0].y;
1655 int nn=nisols-1;
1656 DbgLv(1) << "AA:CP: soln x,y" << mrec.isolutes[nn].x << mrec.isolutes[nn].y;
1657 }
1658 
1659 // Generate the model that goes with the BFM record
1661 {
1662  US_Model modela;
1663  US_Model::SimulationComponent zcomponent;
1664  zcomponent.vbar20 = dset0->vbar20;
1665  nisols = mrec.isolutes.size();
1666  ncsols = mrec.csolutes.size();
1667 
1668  model = mrec.model; // Model to pass back to main
1669  model.components.resize( ncsols );
1670  modela = model; // Model for application (corrected)
1671  double sfactor = 1.0 / dset0->s20w_correction;
1672  double dfactor = 1.0 / dset0->D20w_correction;
1673  double rmsdsv = mrec.rmsd;
1674 
1675  // Build the model that goes along with the new composite model record
1676  for ( int cc = 0; cc < ncsols; cc++ )
1677  {
1678  model.components[ cc ] = zcomponent;
1679  model.components[ cc ].s = mrec.csolutes[ cc ].x;
1680  model.components[ cc ].f_f0 = mrec.csolutes[ cc ].y;
1681  model.components[ cc ].signal_concentration
1682  = mrec.csolutes[ cc ].c;
1683  model.components[ cc ].name = QString().sprintf( "SC%04d", cc + 1 );
1684 
1686 
1687  modela.components[ cc ] = model.components[ cc ];
1688  modela.components[ cc ].s *= sfactor;
1689  modela.components[ cc ].D *= dfactor;
1690  }
1691 
1692  // Do a fit with the composite model and get the RMSD
1693  edata = &dset0->run_data;
1694  US_DataIO::RawData* sdata = &mrec.sim_data;
1695  US_DataIO::RawData* rdata = &mrec.residuals;
1696  US_AstfemMath::initSimData( *sdata, *edata, 0.0 );
1697  US_AstfemMath::initSimData( *rdata, *edata, 0.0 );
1698 
1699  US_Astfem_RSA astfem_rsa( modela, dset0->simparams );
1700  astfem_rsa.calculate( *sdata );
1701 
1702  int nscans = edata->scanCount();
1703  int npoints = edata->pointCount();
1704  double varia = 0.0;
1705 
1706  for ( int ss = 0; ss < nscans; ss++ )
1707  {
1708  for ( int rr = 0; rr < npoints; rr++ )
1709  {
1710  double rval = edata->value( ss, rr ) - sdata->value( ss, rr );
1711  varia += sq( rval );
1712  rdata->setValue( ss, rr, rval );
1713  }
1714  }
1715 
1716  varia /= (double)( nscans * npoints );
1717  double rmsd = sqrt( varia );
1718 
1719  if ( rmsd > rmsdsv && rmsd > mrecs[ 3 ].rmsd )
1720  { // Computed rmsd too high: must have skipped noise, so ignore
1721  mrecs[ 0 ].sim_data = mrec.sim_data;
1722  mrecs[ 0 ].residuals = mrec.residuals;
1723  mrec = mrecs[ 0 ];
1724  model = mrec.model;
1725 
1726  if ( ! mrec.modelGUID.isEmpty() )
1727  { // If possible, load the model referred to in best model record
1728  US_Passwd pw;
1729  bool loadDB = dset0->requestID.contains( "DB" );
1730  US_DB2* dbP = loadDB ? new US_DB2( pw.getPasswd() ) : NULL;
1731 
1732  model.load( loadDB, mrec.modelGUID, dbP );
1733 
1734  mrec.model = model;
1735  mrecs[ 0 ] = mrec;
1736  }
1737  return;
1738  }
1739 
1740  mrec.variance = varia;
1741  mrec.rmsd = sqrt( varia );
1742  mrec.model = model;
1743  mrecs[ 0 ] = mrec;
1744 }
1745 
1746 // Display status message for model records
1747 void US_AdvAnalysisPc::stat_mrecs( const QString msg, bool append, int line )
1748 {
1749  show_stat( te_mrecstat, msg, append, line );
1750 }
1751 
1752 // Display status message for best final model
1753 void US_AdvAnalysisPc::stat_bfm( const QString msg, bool append, int line )
1754 {
1755  show_stat( te_bfmstat, msg, append, line );
1756 }
1757 
1758 // Display status message to a text edit with append and line options
1759 void US_AdvAnalysisPc::show_stat( QTextEdit* tedit, const QString msg,
1760  bool append, int aft_line )
1761 {
1762  if ( append )
1763  { // Message gets appended
1764  QString sttext = tedit->toPlainText();
1765 
1766  if ( aft_line > 0 )
1767  { // Append after the specified line
1768  QStringList stlines = sttext.split( "\n" ); // Get the lines
1769  sttext.clear();
1770 
1771  for ( int ii = 0; ii < qMin( aft_line, stlines.size() ); ii++ )
1772  { // Rebuild lines before the specified one
1773  sttext += stlines[ ii ] + "\n";
1774  }
1775  }
1776 
1777  else
1778  { // Append to full current text
1779  sttext += "\n";
1780  }
1781 
1782  tedit->setText( sttext + msg );
1783  }
1784 
1785  else
1786  { // Message fully replaces content
1787  tedit->setText( msg );
1788  }
1789 }
1790 
1791 // Set the fitting control counters from model records
1792 void US_AdvAnalysisPc::set_fittings( QVector< US_ModelRecord >& s_mrecs )
1793 {
1794  US_ModelRecord s_mrec = s_mrecs[ 0 ];
1795  nisols = s_mrec.isolutes.size();
1796  nmrecs = s_mrecs.size();
1797  int ctype = s_mrec.ctype;
1798 #if 0
1799  int stype = s_mrec.stype;
1800  int attr_x = ( stype >> 6 ) & 7;
1801  int attr_y = ( stype >> 3 ) & 7;
1802  double xscl = ( attr_x == US_ZSolute::ATTR_S ) ? 1.0e13 : 1.0;
1803  double yscl = ( attr_y == US_ZSolute::ATTR_S ) ? 1.0e13 : 1.0;
1804 #endif
1805  double xmin = s_mrec.xmin;
1806  double xmax = s_mrec.xmax;
1807  double ymin = s_mrec.ymin;
1808  double ymax = s_mrec.ymax;
1809  ctype = s_mrec.ctype;
1810 DbgLv(1) << "AA:SF: ctype x,y min,max" << ctype << xmin << xmax
1811  << ymin << ymax;
1812  le_y_strpt ->setText( QString::number( s_mrec.str_y ) );
1813  le_y_endpt ->setText( QString::number( s_mrec.end_y ) );
1814  le_sigmpar1->setText( QString::number( s_mrec.par1 ) );
1815  le_sigmpar2->setText( QString::number( s_mrec.par2 ) );
1816 
1817 #if 0
1818  for ( int ii = 0; ii < nmrecs; ii++ )
1819  {
1820  s_mrec = s_mrecs[ ii ];
1821  ymin = qMin( ymin, s_mrec.str_y );
1822  ymax = qMax( ymax, s_mrec.end_y );
1823  nisols = s_mrec.isolutes.size();
1824 
1825  for ( int jj = 0; jj < nisols; jj++ )
1826  {
1827  double xval = s_mrec.isolutes[ jj ].x * xscl;
1828  double yval = s_mrec.isolutes[ jj ].y * yscl;
1829  xmin = qMin( xmin, xval );
1830  xmax = qMax( xmax, xval );
1831  ymin = qMin( ymin, yval );
1832  ymax = qMax( ymax, yval );
1833 if(xval==0.0 || yval==0.0)
1834 DbgLv(1) << "AA:SF: ii jj ni" << ii << jj << nisols << "x y" << xval << yval;
1835  }
1836  }
1837 #endif
1838 
1839  int ctypex = 0;
1840  ctypex = ( ctype == CTYPE_SL ) ? 0 : ctypex;
1841  ctypex = ( ctype == CTYPE_IS ) ? 1 : ctypex;
1842  ctypex = ( ctype == CTYPE_DS ) ? 2 : ctypex;
1843  ctypex = ( ctype == CTYPE_HL ) ? 3 : ctypex;
1844  ctypex = ( ctype == CTYPE_2O ) ? 4 : ctypex;
1845  cb_curvtype->setCurrentIndex( ctypex );
1846  le_x_lower ->setText( QString::number( xmin ) );
1847  le_x_upper ->setText( QString::number( xmax ) );
1848  le_y_lower ->setText( QString::number( ymin ) );
1849  le_y_upper ->setText( QString::number( ymax ) );
1850  le_crpoints->setText( QString::number( nisols ) );
1851 DbgLv(1) << "AA:SF: (2) x,y min,max" << ctype << xmin << xmax << ymin << ymax;
1852 }
1853 
1854 // Return a flag and possibly warn if operation requires valid mrecs
1856 {
1857  // Test the mrecs list for validity
1858  bool needMrs = ( mrecs.size() < 2 || mrecs[ 1 ].csolutes.size() < 1 );
1859 
1860  // Output a warning dialog if not
1861  if ( needMrs )
1862  {
1863  QMessageBox::critical( this, tr( "Invalid Operation" ),
1864  tr( "<b>%1</b> is not a valid operation<br/>"
1865  "&nbsp;&nbsp;when no Model Records have been computed.<br/>"
1866  "Your options at this point are:"
1867  "<ul><li>Go back to the main analysis controls window and do"
1868  " a fit with <b>Start Fit</b>, then return here to retry; or"
1869  "</li><li>Do a <b>Load Model Records</b> here, and then\n"
1870  " retry this operation.</li></ul>" ).arg( oper ) );
1871  }
1872 
1873  return needMrs;
1874 }
1875 
1876 // Return a flag and possibly warn if operation incompatible
1877 bool US_AdvAnalysisPc::bfm_incompat( QString fname )
1878 {
1879  // Test the compatibility of a new BFM with existing mrecs
1880  bool inCompat = false;
1881 
1882  int ftype = mrec.ctype;
1883  double fxmin = mrec.xmin;
1884  double fxmax = mrec.xmax;
1885  double fymin = mrec.ymin;
1886  double fymax = mrec.ymax;
1887  int rtype = mrecs[ 1 ].ctype;
1888  double rxmin = mrecs[ 1 ].xmin;
1889  double rxmax = mrecs[ 1 ].xmax;
1890  double rymin = mrecs[ 1 ].ymin;
1891  double rymax = mrecs[ 1 ].ymax;
1892 DbgLv(1) << "AA:BI: ftype rtype" << ftype << rtype << "fname" << fname;
1893 
1894  inCompat = ( inCompat || ( ftype != rtype ) );
1895 DbgLv(1) << "AA:BI: (1)inCompat" << inCompat;
1896  inCompat = ( inCompat || ( fxmin > rxmax ) );
1897  inCompat = ( inCompat || ( fxmax < rxmin ) );
1898  inCompat = ( inCompat || ( fymin > rymax ) );
1899  inCompat = ( inCompat || ( fymax < rymin ) );
1900 DbgLv(1) << "AA:BI: (5)inCompat" << inCompat;
1901 
1902  if ( inCompat )
1903  {
1904  const char* ctps[] = { "Straight Line",
1905  "Increasing Sigmoid",
1906  "Decreasing Sigmoid",
1907  "Horizontal Line" };
1908  int ftx = ftype;
1909  ftx = ( ftype == CTYPE_SL ) ? 0 : ftx;
1910  ftx = ( ftype == CTYPE_IS ) ? 1 : ftx;
1911  ftx = ( ftype == CTYPE_DS ) ? 2 : ftx;
1912  ftx = ( ftype == CTYPE_HL ) ? 3 : ftx;
1913  int rtx = rtype;
1914  rtx = ( rtype == CTYPE_SL ) ? 0 : rtx;
1915  rtx = ( rtype == CTYPE_IS ) ? 1 : rtx;
1916  rtx = ( rtype == CTYPE_DS ) ? 2 : rtx;
1917  rtx = ( rtype == CTYPE_HL ) ? 3 : rtx;
1918  QString fpars = QString( ctps[ ftx ] )
1919  + tr( " ; s %1 to %2 ; f/f0 %3 to %4" )
1920  .arg( fxmin ).arg( fxmax ).arg( fymin ).arg( fymax );
1921  QString rpars = QString( ctps[ rtx ] )
1922  + tr( " ; s %1 to %2 ; f/f0 %3 to %4" )
1923  .arg( rxmin ).arg( rxmax ).arg( rymin ).arg( rymax );
1924 
1925  QMessageBox::critical( this, tr( "Incompatible Final Model" ),
1926  tr( "File <b>%1</b> has fitting controls incompatible<br/>"
1927  "&nbsp;&nbsp;with the existing model records."
1928  "<ul><li>File:&nbsp;&nbsp;%2.</li>"
1929  "<li>Records:&nbsp;&nbsp;%3.</li></ul>" )
1930  .arg( fname ).arg( fpars ).arg( rpars ) );
1931 
1932  mrec = mrecs[ 0 ];
1933  }
1934 
1935  return inCompat;
1936 }
1937 
1938 // Test procedures for handling pcsa_modelrecs table
1940 {
1941  US_Passwd pw;
1942  US_DB2* dbP = new US_DB2( pw.getPasswd() );
1943  int mrID1 = -1;
1944  QString invID = QString::number( US_Settings::us_inv_ID() );
1945  QStringList qry;
1946 
1947  qry.clear();
1948  qry << "count_mrecs" << invID;
1949 qDebug() << "QRY:" << qry;
1950  int nmrec = dbP->functionQuery( qry );
1951 qDebug() << " nmrec" << nmrec;
1952 qDebug() << " nm stat" << dbP->lastErrno() << dbP->lastError();
1953 
1954  qry.clear();
1955  qry << "get_mrecs_desc" << invID;
1956 qDebug() << "QRY:" << qry;
1957  dbP->query( qry );
1958  if ( dbP->lastErrno() == US_DB2::OK )
1959  {
1960 qDebug() << " numRows" << dbP->numRows();
1961 qDebug() << " nR stat" << dbP->lastErrno() << dbP->lastError();
1962  while ( dbP->next() )
1963  {
1964  int mrID = dbP->value( 0 ).toInt();
1965  mrID1 = ( mrID1 < 0 ) ? mrID : mrID1;
1966  QString mrGUID = dbP->value( 1 ).toString();
1967  int edID = dbP->value( 2 ).toInt();
1968  QString edGUID = dbP->value( 3 ).toString();
1969  int moID = dbP->value( 4 ).toInt();
1970  QString moGUID = dbP->value( 5 ).toString();
1971  QString descr = dbP->value( 6 ).toString();
1972  QString cksm = dbP->value( 7 ).toString();
1973  QString size = dbP->value( 8 ).toString();
1974  QString utime = dbP->value( 9 ).toString();
1975 qDebug() << " mrID mrGUID" << mrID << mrGUID;
1976 qDebug() << " edID edGUID" << edID << edGUID;
1977 qDebug() << " moID moGUID" << moID << moGUID;
1978 qDebug() << " desc" << descr;
1979 qDebug() << " cksm size" << cksm << size;
1980 qDebug() << " utime" << utime;
1981  }
1982  }
1983 
1984  qry.clear();
1985  qry << "get_mrecs_desc" << "0";
1986 qDebug() << "QRY:" << qry;
1987  dbP->query( qry );
1988  if ( dbP->lastErrno() == US_DB2::OK )
1989  {
1990 qDebug() << " numRows" << dbP->numRows();
1991 qDebug() << " nR stat" << dbP->lastErrno() << dbP->lastError();
1992  while ( dbP->next() )
1993  {
1994  int mrID = dbP->value( 0 ).toInt();
1995  QString mrGUID = dbP->value( 1 ).toString();
1996  int edID = dbP->value( 2 ).toInt();
1997  QString edGUID = dbP->value( 3 ).toString();
1998  int moID = dbP->value( 4 ).toInt();
1999  QString moGUID = dbP->value( 5 ).toString();
2000  QString descr = dbP->value( 6 ).toString();
2001  QString cksm = dbP->value( 7 ).toString();
2002  QString size = dbP->value( 8 ).toString();
2003  QString utime = dbP->value( 9 ).toString();
2004 qDebug() << " mrID mrGUID" << mrID << mrGUID;
2005 qDebug() << " edID edGUID" << edID << edGUID;
2006 qDebug() << " moID moGUID" << moID << moGUID;
2007 qDebug() << " desc" << descr;
2008 qDebug() << " cksm size" << cksm << size;
2009 qDebug() << " utime" << utime;
2010  }
2011  }
2012 
2013  else
2014  {
2015 qDebug() << " *ERROR*" << dbP->lastErrno() << dbP->lastError();
2016  }
2017 
2018  qry.clear();
2019  QString edGUID = dset0->run_data.editGUID;
2020  qry << "get_editID" << edGUID;
2021 qDebug() << "QRY:" << qry;
2022  dbP->query( qry );
2023  QString editID = dbP->value( 0 ).toString();
2024 qDebug() << " editID edGUID" << editID << edGUID;
2025 
2026  qry.clear();
2027  qry << "count_mrecs_by_editID" << invID << editID;
2028 qDebug() << "QRY:" << qry;
2029  int nmredt = dbP->functionQuery( qry );
2030 qDebug() << " nmredt" << nmredt;
2031 qDebug() << " nm stat" << dbP->lastErrno() << dbP->lastError();
2032 
2033  qry.clear();
2034  qry << "get_mrecs_desc_by_editID" << invID << editID;
2035 qDebug() << "QRY:" << qry;
2036  dbP->query( qry );
2037  if ( dbP->lastErrno() == US_DB2::OK )
2038  {
2039 qDebug() << " numRows" << dbP->numRows();
2040 qDebug() << " nR stat" << dbP->lastErrno() << dbP->lastError();
2041  while ( dbP->next() )
2042  {
2043  int mrID = dbP->value( 0 ).toInt();
2044  QString mrGUID = dbP->value( 1 ).toString();
2045  int edID = dbP->value( 2 ).toInt();
2046  QString edGUID = dbP->value( 3 ).toString();
2047  int moID = dbP->value( 4 ).toInt();
2048  QString moGUID = dbP->value( 5 ).toString();
2049  QString descr = dbP->value( 6 ).toString();
2050  QString cksm = dbP->value( 7 ).toString();
2051  QString size = dbP->value( 8 ).toString();
2052  QString utime = dbP->value( 9 ).toString();
2053 qDebug() << " mrID mrGUID" << mrID << mrGUID;
2054 qDebug() << " edID edGUID" << edID << edGUID;
2055 qDebug() << " moID moGUID" << moID << moGUID;
2056 qDebug() << " desc" << descr;
2057 qDebug() << " cksm size" << cksm << size;
2058 qDebug() << " utime" << utime;
2059  }
2060  }
2061 
2062  else
2063  {
2064 qDebug() << " *ERROR*" << dbP->lastErrno() << dbP->lastError();
2065  }
2066 
2067  qry.clear();
2068  qry << "get_mrecs_info" << QString::number( mrID1 );
2069 qDebug() << "QRY:" << qry;
2070  dbP->query( qry );
2071  if ( dbP->lastErrno() == US_DB2::OK )
2072  {
2073 qDebug() << " numRows" << dbP->numRows();
2074 qDebug() << " nR stat" << dbP->lastErrno() << dbP->lastError();
2075  dbP->next();
2076  QString mrGUID = dbP->value( 0 ).toString();
2077  QString xmlstr = dbP->value( 1 ).toString();
2078  int edID = dbP->value( 2 ).toInt();
2079  QString edGUID = dbP->value( 3 ).toString();
2080  int moID = dbP->value( 4 ).toInt();
2081  QString moGUID = dbP->value( 5 ).toString();
2082  QString descr = dbP->value( 6 ).toString();
2083  QString cksm = dbP->value( 7 ).toString();
2084  int xsize = dbP->value( 8 ).toInt();
2085  QString utime = dbP->value( 9 ).toString();
2086 qDebug() << " mrID mrGUID" << mrID1 << mrGUID;
2087 qDebug() << " edID edGUID" << edID << edGUID;
2088 qDebug() << " moID moGUID" << moID << moGUID;
2089 qDebug() << " desc" << descr;
2090 qDebug() << " cksm size" << cksm << xsize << "xml len" << xmlstr.length();
2091  QString xmls1 = QString( xmlstr ).left ( 1600 );
2092  QString xmls2 = QString( xmlstr ).right( 1600 );
2093 qDebug() << "==== XML1" << xmls1 << "XML1 ======";
2094 qDebug() << "==== XML2" << xmls2 << "XML2 ======";
2095  }
2096 
2097  else
2098  {
2099 qDebug() << " *ERROR*" << dbP->lastErrno() << dbP->lastError();
2100  }
2101 }
2102