UltraScan III
us_sassoc.cpp
Go to the documentation of this file.
1 #include "us_sassoc.h"
3 #include "us_gui_settings.h"
4 #include "us_settings.h"
5 #include "us_constants.h"
6 
7 #include "qwt_scale_engine.h"
8 
9 US_Sassoc::US_Sassoc( double eq0, double eq1, double stoich1, double stoich2,
10  const QString& t_project, int t_model, bool status,
11  bool position_win, QWidget* parent, Qt::WindowFlags flags )
12  : US_Widgets( position_win, parent, flags )
13 {
14  eq[ 0 ] = eq0;
15  eq[ 1 ] = eq1;
16  model = t_model;
17  stoich[ 0 ] = stoich1;
18  stoich[ 1 ] = stoich2;
19  project = t_project;
20  updating = false;
21 
22  setPalette( US_GuiSettings::frameColor() );
23  setWindowTitle( tr( "Equilibrium Concentration Distribution" ) );
24 
25  QBoxLayout* main = new QHBoxLayout( this );
26  main->setContentsMargins( 2, 2, 2, 2 );
27  main->setSpacing( 2 );
28 
29  QBoxLayout* controls = new QVBoxLayout;
30 
31  QLabel* lb_header= us_banner( tr( "Species Distribution in\n"
32  "Self-Associating System" ), -2 );
33  lb_header->setMargin( 10 );
34  controls->addWidget( lb_header );
35 
36  QLabel* lb_stoich= us_banner( tr( "Stoichiometries:" ), -2 );
37  controls->addWidget( lb_stoich );
38 
39  // Association constants
40  QGridLayout* params = new QGridLayout;
41  int row = 0;
42 
43  QLabel* lb_assoc1 = us_label( "Association1:" );
44  params->addWidget( lb_assoc1, row, 0 );
45 
46  le_assoc1 = us_lineedit( QString::number( stoich1, 'f', 4 ) );
47  connect( le_assoc1, SIGNAL( textChanged ( const QString& ) ),
48  SLOT( update_stoich1( const QString& ) ) );
49  params->addWidget( le_assoc1, row++, 1 );
50 
51  QLabel* lb_assoc2 = us_label( "Association2:" );
52  params->addWidget( lb_assoc2, row, 0 );
53 
54  le_assoc2 = us_lineedit( QString::number( stoich2, 'f', 4 ) );
55  connect( le_assoc2, SIGNAL( textChanged ( const QString& ) ),
56  SLOT( update_stoich2( const QString& ) ) );
57  params->addWidget( le_assoc2, row++, 1 );
58 
59  // Equlibrium constants
60  QLabel* lb_equil= us_banner( tr( "Equilibrium Constants:" ), -2 );
61  params->addWidget( lb_equil, row++, 0, 1, 2 );
62 
63  QLabel* lb_equil1 = us_label( "ln( Constant1 ):" );
64  params->addWidget( lb_equil1, row, 0 );
65 
66  le_equil1 = us_lineedit( QString::number( eq0, 'g', 3 ) );
67  connect( le_equil1, SIGNAL( textChanged( const QString& ) ),
68  SLOT ( update_eq1 ( const QString& ) ) );
69  params->addWidget( le_equil1, row++, 1 );
70 
71  c_equil1 = us_counter( 3, -100.0, 100.0, eq0 );
72  c_equil1->setStep( 0.01 );
73  connect( c_equil1, SIGNAL( valueChanged ( double ) ),
74  SLOT ( update_eq1Count( double ) ) );
75  params->addWidget( c_equil1, row++, 0, 1, 2 );
76 
77  QLabel* lb_equil2 = us_label( "ln( Constant2 ):" );
78  params->addWidget( lb_equil2, row, 0 );
79 
80  le_equil2 = us_lineedit( QString::number( eq1, 'g', 3 ) );
81  connect( le_equil2, SIGNAL( textChanged( const QString& ) ),
82  SLOT ( update_eq2 ( const QString& ) ) );
83  params->addWidget( le_equil2, row++, 1 );
84 
85  c_equil2 = us_counter( 3, -100.0, 100.0, eq1 );
86  c_equil2->setStep( 0.01 );
87  connect( c_equil2, SIGNAL( valueChanged ( double ) ),
88  SLOT ( update_eq2Count( double ) ) );
89  params->addWidget( c_equil2, row++, 0, 1, 2 );
90 
91  controls->addLayout( params );
92 
93  // Other data
94  QLabel* lb_model= us_banner( tr( "Equilibrium Model:" ), -2 );
95  controls->addWidget( lb_model );
96 
97  QStringList models = US_Constants::modelStrings();
98 
99  QTextEdit* te_model = us_textedit();
100  te_model->setText( models[ model ] );
101  te_model->setReadOnly( true );
102  te_model->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
103  te_model->setMaximumHeight( 100 );
104  QPalette p = US_GuiSettings::editColor();
105  p.setColor( QPalette::Base, Qt::lightGray );
106  te_model->setPalette( p );
107  controls->addWidget( te_model );
108 
109  QLabel* lb_project= us_banner( tr( "Project Name:" ), -2 );
110  controls->addWidget( lb_project );
111 
112  QLineEdit* le_project = us_lineedit( project );
113  le_project->setReadOnly( true );
114  le_project->setPalette( p );
115  controls->addWidget( le_project );
116 
117  controls->addStretch();
118 
119  // Buttons
120  QPushButton* pb_save = us_pushbutton( tr( "Save Data to File" ) );
121  connect( pb_save, SIGNAL( clicked() ), SLOT( save() ) );
122  controls->addWidget( pb_save );
123 
124  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
125  connect( pb_help, SIGNAL( clicked() ), SLOT( help() ) );
126  controls->addWidget( pb_help );
127 
128  QPushButton* pb_close = us_pushbutton( tr( "Close" ) );
129  connect( pb_close, SIGNAL( clicked() ), SLOT( close() ) );
130  controls->addWidget( pb_close );
131 
132  main->addLayout( controls );
133  QBoxLayout* rightSide = new QVBoxLayout;
134 
135  // Graph
136  plot1 = new US_Plot( plot,
137  tr( "Self-Association Profile for" ) + project,
138  tr( "Total Concentration" ),
139  tr( "% of Total Concentration" ) );
140 
141  plot->setAxisScaleEngine( QwtPlot::xBottom, new QwtLog10ScaleEngine );
142  pick = new US_PlotPicker( plot );
143  pick->setRubberBand( QwtPicker::VLineRubberBand );
144  connect( pick, SIGNAL( selected ( const QwtDoublePoint& ) ),
145  SLOT ( new_value( const QwtDoublePoint& ) ) );
146  connect( pick, SIGNAL( moved ( const QwtDoublePoint& ) ),
147  SLOT ( new_value( const QwtDoublePoint& ) ) );
148  connect( pick, SIGNAL( mouseDown( const QwtDoublePoint& ) ),
149  SLOT ( mouseD ( const QwtDoublePoint& ) ) );
150  connect( pick, SIGNAL( mouseUp ( const QwtDoublePoint& ) ),
151  SLOT ( mouseU ( const QwtDoublePoint& ) ) );
152 
153  // Initialize x
154  double c = 1.0e-10; // Lower concentration range limit
155  const double inc = 20.0;
156 
157  for ( int i = 0; i < ARRAY_SIZE; i++ )
158  {
159  x[ i ] = c;
160  c += c / inc;
161  }
162 
163  curve1 = us_curve( plot, tr( "Species 1" ) );
164  curve2 = us_curve( plot, tr( "Species 2" ) );
165  curve3 = us_curve( plot, tr( "Species 3" ) );
166 
167  curve1->setPen( QPen( QBrush( Qt::green ), 2.0 ) );
168  curve2->setPen( QPen( QBrush( Qt::yellow ), 2.0 ) );
169  curve3->setPen( QPen( QBrush( Qt::cyan ), 2.0 ) );
170 
171  recalc();
172 
173  QGridLayout* legend = new QGridLayout;
174 
176  QLabel* lb_species1= us_label( tr( "Species 1:" ) );
177  p.setColor( QPalette::WindowText, Qt::green );
178  lb_species1->setPalette( p );
179  legend->addWidget( lb_species1, 0, 0 );
180 
181  le_species1 = us_lineedit( "0 %" );
182  le_species1->setReadOnly( true );
183  legend->addWidget( le_species1, 0, 1 );
184 
185  QLabel* lb_species2= us_label( tr( "Species 2:" ) );
186  p.setColor( QPalette::WindowText, Qt::yellow );
187  lb_species2->setPalette( p );
188  legend->addWidget( lb_species2, 0, 2 );
189 
190  le_species2 = us_lineedit( "0 %" );
191  le_species2->setReadOnly( true );
192  legend->addWidget( le_species2, 0, 3 );
193 
194  QLabel* lb_species3= us_label( tr( "Species 3:" ) );
195  p.setColor( QPalette::WindowText, Qt::cyan );
196  lb_species3->setPalette( p );
197  legend->addWidget( lb_species3, 0, 4 );
198 
199  le_species3 = us_lineedit( "0 %" );
200  le_species3->setReadOnly( true );
201  legend->addWidget( le_species3, 0, 5 );
202 
203  QLabel* conc = us_label( tr( "Total Concentration:" ) );
204  legend->addWidget( conc, 1, 0 );
205 
206  le_conc = us_lineedit( "0 M" );
207  le_species3->setReadOnly( true );
208  legend->addWidget( le_conc, 1, 1 );
209 
210  QLineEdit* le_conc = us_lineedit(
211  tr( "Drag mouse through plot area to see relative concentrations" ) );
212  le_species3->setReadOnly( true );
213  legend->addWidget( le_conc, 1, 2, 1, 4 );
214 
215  rightSide->addLayout( plot1 );
216  rightSide->addLayout( legend);
217  main->addLayout( rightSide);
218  status = ! status; // Avoid warning for now
219 }
220 
221 void US_Sassoc::recalc( void )
222 {
223  for ( int i = 0; i < ARRAY_SIZE; i++ )
224  {
225  species1[ i ] = monomer_root( x[ i ] );
226  species2[ i ] = stoich[ 0 ] * pow( species1[ i ], stoich[ 0 ]) * exp( eq[ 0 ] );
227  species3[ i ] = stoich[ 1 ] * pow( species1[ i ], stoich[ 1 ]) * exp( eq[ 1 ] );
228 
229  species1[ i ] *= 100 / x[ i ];
230  species2[ i ] *= 100 / x[ i ];
231  species3[ i ] *= 100 / x[ i ];
232  }
233 
234  curve1->setData( x, species1, ARRAY_SIZE );
235  curve2->setData( x, species2, ARRAY_SIZE );
236  curve3->setData( x, species3, ARRAY_SIZE );
237  plot->replot();
238 
239 }
240 
241 double US_Sassoc::monomer_root( double total )
242 {
243  double monomer = total / 2;
244  double diff = monomer / 2;
245  double diff1 = monomer - diff; // = total / 4
246  double test = polynomial( monomer, total );
247 
248  while ( fabs( diff1 ) > 1.0e-15 )
249  {
250  double monomer_old = monomer;
251 
252  if ( test > 0 )
253  monomer = monomer - diff;
254  else
255  monomer = monomer + diff;
256 
257  test = polynomial( monomer, total );
258  diff = fabs( monomer - monomer_old ) / 2;
259  diff1 = monomer_old - monomer;
260  }
261 
262  return monomer;
263 }
264 
265 double US_Sassoc::polynomial( double monomer, double total )
266 {
267  return monomer +
268  stoich[ 0 ] * pow( monomer, stoich[ 0 ] ) * exp( eq[ 0 ] ) +
269  stoich[ 1 ] * pow( monomer, stoich[ 1 ] ) * exp( eq[ 1 ] ) -
270  total;
271 }
272 
273 void US_Sassoc::new_value( const QwtDoublePoint& p )
274 {
275  update_legend( p.x() );
276 }
277 
278 void US_Sassoc::mouseU( const QwtDoublePoint& /* p */)
279 {
280  update_legend( -1.0 );
281 }
282 
283 void US_Sassoc::mouseD( const QwtDoublePoint& p )
284 {
285  updating = true;
286  update_legend( p.x() );
287 }
288 
289 void US_Sassoc::update_legend( const double total )
290 {
291  if ( total >= 1.0e-10 && total <= 100.0 && updating )
292  {
293  int i = 0;
294  while ( x[ i ] < total ) i++;
295 
296  le_species1->setText( QString::number( curve1->y( i ) ) + " %" );
297  le_species2->setText( QString::number( curve2->y( i ) ) + " %" );
298  le_species3->setText( QString::number( curve3->y( i ) ) + " %" );
299  le_conc ->setText( QString::number( total ) + " M" );
300  }
301  else
302  {
303  updating = false;
304  le_species1->setText( " 0 %" );
305  le_species2->setText( " 0 %" );
306  le_species3->setText( " 0 %" );
307  le_conc ->setText( " 0 M" );
308  }
309 }
310 
311 void US_Sassoc::update_stoich1( const QString& s )
312 {
313  stoich[ 0 ] = s.toDouble();
314  recalc();
315 }
316 
317 void US_Sassoc::update_stoich2( const QString& s )
318 {
319  stoich[ 1 ] = s.toDouble();
320  recalc();
321 }
322 
323 void US_Sassoc::update_eq1( const QString& s )
324 {
325  eq[ 0 ] = s.toDouble();
326  c_equil1->setValue( eq[ 0 ] );
327  recalc();
328 }
329 
330 void US_Sassoc::update_eq2( const QString& s )
331 {
332  eq[ 1 ] = s.toDouble();
333  c_equil2->setValue( eq[ 1 ] );
334  recalc();
335 }
336 
337 void US_Sassoc::update_eq1Count( double value )
338 {
339  eq[ 0 ] = value;
340  le_equil1->setText( QString::number( value ) );
341  // No need to call recalc(), since this will signal textChanged() in lineedit
342 }
343 
344 void US_Sassoc::update_eq2Count( double value )
345 {
346  eq[ 1 ] = value;
347  le_equil2->setText( QString::number( value ) );
348  // No need to call recalc(), since this will signal textChanged() in lineedit
349 }
350 
351 void US_Sassoc::save( void )
352 {
353  QString filename = US_Settings::resultDir() + "/" + project + "-" +
354  QString::number( model ) + ".dis";
355 
356  QFile f( filename );
357 
358  if ( f.exists() )
359  {
360  if ( QMessageBox::warning( this,
361  tr( "Warning" ),
362  tr( "Attention:\nThis file exists already!\n\n" )
363  + filename +
364  tr( "\n\nDo you want to overwrite it?" ),
365  QMessageBox::Yes, QMessageBox::No ) == QMessageBox::No )
366  {
367  return;
368  }
369  }
370 
371  // Save the data
372  if ( f.open( QIODevice::WriteOnly | QIODevice::Text ) )
373  {
374  QTextStream ts( &f );
375  ts << tr( "\"Total Concentration\"\t\"% Monomer\"\t\"% " )
376  << stoich[ 0 ] << "-mer\"\t\"% " << stoich[ 1 ] << "-mer\"\n";
377 
378  for ( int i = 0; i < ARRAY_SIZE; i++ )
379  {
380  ts << x [ i ] << "\t"
381  << species1[ i ] << "\t"
382  << species2[ i ] << "\t"
383  << species3[ i ] << endl;
384  }
385  }
386 
387  f.close();
388 
389  // Save a picture
390  QDir dir;
391  QString reportDir = US_Settings::reportDir();
392  if ( ! dir.exists( reportDir ) ) dir.mkpath( reportDir );
393 
394  filename = reportDir + "/" + project + "-" +
395  QString::number( model ) + ".distribution.png";
396 
397  QRect r = QRect( 2, 2, plot->width() - 4, plot->height() - 4 );
398  QPixmap p = QPixmap::grabWidget( plot, r );
399 
400  p.save( filename );
401 }