UltraScan III
us_second_moment.cpp
Go to the documentation of this file.
1 
3 #include <QApplication>
4 
5 #include "us_second_moment.h"
6 #include "us_license_t.h"
7 #include "us_license.h"
8 #include "us_settings.h"
9 #include "us_gui_settings.h"
10 
12 // the class US_Convert.
13 
14 int main( int argc, char* argv[] )
15 {
16  QApplication application( argc, argv );
17 
18  #include "main1.inc"
19 
20  // License is OK. Start up.
21 
23  w.show();
24  return application.exec();
25 }
26 
28 {
29  setWindowTitle( tr( "Second Moment Analysis" ) );
30 
31  smPoints = NULL;
32  smSeconds = NULL;
33  te_results = NULL;
34 
35  connect( pb_help, SIGNAL( clicked() ), SLOT( help() ) );
36  connect( pb_view, SIGNAL( clicked() ), SLOT( view() ) );
37  connect( pb_save, SIGNAL( clicked() ), SLOT( save() ) );
38 }
39 
41 {
43 
44  //time_correction = US_Math::time_correction( dataList );
45 
46  int index = lw_triples->currentRow();
47  US_DataIO::EditedData* d = &dataList[ index ];
48 
49  int scanCount = d->scanCount();
50  int points = d->pointCount();
51  int exclude = 0;
52  double boundaryPct = ct_boundaryPercent->value() / 100.0;
53  double positionPct = ct_boundaryPos ->value() / 100.0;
54  double baseline = calc_baseline();
55 
56  for ( int i = 0; i < scanCount; i++ )
57  {
58  if ( excludedScans.contains( i ) ) continue;
59 
60  double range = d->scanData[ i ].plateau - baseline;
61  double test_y = baseline + range * positionPct;
62 
63  if ( d->scanData[ i ].rvalues[ 0 ] > test_y ) exclude++;
64  }
65 
66  le_skipped->setText( QString::number( exclude ) );
67 
68  // Draw plot
69  data_plot1->clear();
71 
72  data_plot1->setTitle( tr( "Run " ) + d->runID + tr( ": Cell " ) + d->cell
73  + " (" + d->wavelength + tr( " nm)\nSecond Moment Plot" ) );
74 
75  data_plot1->setAxisTitle( QwtPlot::xBottom, tr( "Scan Number" ) );
76  data_plot1->setAxisTitle( QwtPlot::yLeft ,
77  tr( "Corrected Sed. Coeff. (1e-13 s)" ) );
78 
79  if ( smPoints != NULL ) delete [] smPoints;
80  if ( smSeconds != NULL ) delete [] smSeconds;
81 
82  smPoints = new double[ scanCount ];
83  smSeconds = new double[ scanCount ];
84 
85  // Calculate the 2nd moment
86  for ( int i = 0; i < scanCount; i++ )
87  {
88  double sum1 = 0.0;
89  double sum2 = 0.0;
90  int count = 0;
91 
92  // The span is the boundary portion that is going to be analyzed (in
93  // percent)
94 
95  double range = ( d->scanData[ i ].plateau - baseline ) * boundaryPct;
96  double test_y = range * positionPct;
97 
98  while ( d->scanData[ i ].rvalues[ count ] - baseline < test_y )
99  count++;
100 
101 
102  if ( count == 0 ) count = 1;
103 
104  while ( count < points )
105  {
106  double value = d->scanData[ i ].rvalues[ count ] - baseline;
107  double radius = d->xvalues[ count ];
108 
109  if ( value >= test_y + range ) break;
110 
111  double v0 = d->scanData[ i ].rvalues[ count - 1 ] - baseline;
112  double dC = value - v0;
113 
114  sum1 += dC * sq( radius );
115  sum2 += dC;
116  count++;
117  }
118 
119  smPoints [ i ] = sqrt( sum1 / sum2 ); // second moment points in cm
120 
121  double omega = d->scanData[ i ].rpm * M_PI / 30.0;
122 
123  // second moment s
124  smSeconds[ i ] =
125  1.0e13 * solution.s20w_correction * log( smPoints[ i ] / d->meniscus ) /
126  ( sq( omega ) * ( d->scanData[ i ].seconds - time_correction ) );
127  }
128 
129  QVector< double > x( scanCount );
130  QVector< double > y( scanCount );
131 
132  // Sedimentation coefficients from all scans that have not cleared the
133  // meniscus form a separate plot that will be plotted in red, and will not
134  // be included in the line fit:
135 
136  QwtPlotCurve* curve;
137  QwtSymbol sym;
138 
139  int count = 0;
140 
141  // Curve 1
142  for ( int i = 0; i < exclude; i++ )
143  {
144  if ( excludedScans.contains( i ) ) continue;
145 
146  x[ count ] = (double)( count + 1 );
147  y[ count ] = smSeconds[ i ];
148  count++;
149  }
150 
151  curve = us_curve( data_plot1, tr( "Non-cleared Sedimentation Coefficients" ) );
152 
153  sym.setStyle( QwtSymbol::Ellipse );
154  sym.setPen ( QPen( Qt::white ) );
155  sym.setBrush( QBrush( Qt::red ) );
156  sym.setSize ( 8 );
157 
158  curve->setStyle ( QwtPlotCurve::NoCurve );
159  curve->setSymbol( sym );
160  curve->setData ( x.data(), y.data(), count );
161 
162  // Curve 2
163  count = 0;
164  double average = 0.0;
165 
166  for ( int i = exclude; i < scanCount; i++ )
167  {
168  if ( excludedScans.contains( i ) ) continue;
169 
170  x[ count ] = (double)( count + 1 + exclude );
171  y[ count ] = smSeconds[ i ];
172  average += smSeconds[ i ];
173  count++;
174  }
175 
176  average_2nd = (count > 0 ) ? average / count : 0.0;
177 
178  sym.setPen ( QPen ( Qt::blue ) );
179  sym.setBrush( QBrush( Qt::white ) );
180 
181  curve = us_curve( data_plot1, tr( "Cleared Sedimentation Coefficients" ) );
182  curve->setSymbol( sym );
183  curve->setData( x.data(), y.data(), count );
184 
185  // Curve 3
186  x[ 0 ] = 0.0;
187  x[ 1 ] = (double)( scanCount - excludedScans.size() );
188  y[ 0 ] = average_2nd;
189  y[ 1 ] = average_2nd;
190 
191  if ( count > 0 )
192  {
193  curve = us_curve( data_plot1, tr( "Average" ) );
194  curve->setPen( QPen( Qt::green ) );
195  curve->setData( x.data(), y.data(), 2 );
196  }
197 
198  data_plot1->setAxisScale ( QwtPlot::xBottom, 0.0, x[ 1 ] + 0.25, 0.0 );
199  data_plot1->setAxisMaxMinor( QwtPlot::xBottom, 0 );
200 
201  // Mark excluded
202  int from = (int)ct_from->value();
203  int to = (int)ct_to ->value();
204 
205  if ( to > 0 )
206  {
207  int index = 0;
208 
209  for ( int i = 0; i < scanCount; i++ )
210  {
211  if ( excludedScans.contains( i ) ) continue;
212 
213  index++;
214  if ( index < from ) continue;
215  if ( index > to ) break;
216 
217  x[ 0 ] = index;
218  x[ 1 ] = x[ 0 ];
219  y[ 0 ] = smSeconds[ i ] + 0.5;
220  y[ 1 ] = smSeconds[ i ] - 0.5;;
221 
222  curve = us_curve( data_plot1,
223  tr( "Scan %1 Exclude Marker" ).arg( index + 1 ) );
224 
225  curve->setPen( QPen( QBrush( Qt::red ), 1.0 ) );
226  curve->setData( x.data(), y.data(), 2 );
227  }
228  }
229 
230  data_plot1->replot();
231 }
232 
234 {
236  pb_reset_exclude->setEnabled( true );
237 }
238 
239 void US_SecondMoment::write_report( QTextStream& ts )
240 {
241  int index = lw_triples->currentRow();
242  US_DataIO::EditedData* edata = &dataList[ index ];
243 
244  QString sm_results =
245  table_row( tr( "Average Second Moment S: " ),
246  QString::number( average_2nd, 'f', 5 ) + " s * 10e-13" );
247 
248  ts << html_header( QString( "US_Second_Moment" ),
249  QString( "Second Moment Analysis" ),
250  edata );
251  ts << analysis( sm_results );
252  ts << indent( 2 ) + "</body>\n</html>\n";
253 }
254 
256 {
257  // Write main report as string
258  QString rtext;
259  QTextStream ts( &rtext );
260  write_report( ts );
261 
262  // Create US_Editor and display report
263  if ( te_results == NULL )
264  {
265  te_results = new US_Editor( US_Editor::DEFAULT, true, QString(), this );
266  te_results->resize( 600, 700 );
267  QPoint p = g.global_position();
268  te_results->move( p.x() + 30, p.y() + 30 );
269  te_results->e->setFont( QFont( US_GuiSettings::fontFamily(),
271  }
272 
273  te_results->e->setHtml( rtext );
274  te_results->show();
275 }
276 
278 {
279  int index = lw_triples->currentRow();
280  US_DataIO::EditedData* d = &dataList[ index ];
281  QString dir = US_Settings::reportDir();
282 
283  if ( ! mkdir( dir, d->runID ) ) return;
284 
285  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
286  // Note: d->runID is both directory and first segment of file name
287  QString filebase = dir + "/" + d->runID + "/secmo."
288  + QString( triples.at( index ) ).replace( " / ", "" ) + ".";
289 
290  QString plot1File = filebase + "2ndmoment.svgz";
291  QString plot2File = filebase + "velocity.svgz";
292  QString textFile = filebase + "2ndmoment.csv";
293  QString htmlFile = filebase + "report.html";
294  QString dsinfFile = QString( filebase ).replace( "/secmo.", "/dsinfo." )
295  + "dataset_info.html";
296 
297  // Write a general dataset information file
298  write_dset_report( dsinfFile );
299 
300  // Write main report
301  QFile reportf( htmlFile );
302 
303  if ( ! reportf.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
304  {
305  QMessageBox::warning( this,
306  tr( "IO Error" ),
307  tr( "Could not open\n" ) + htmlFile + "\n" +
308  tr( "\nfor writing" ) );
309  QApplication::restoreOverrideCursor();
310  return;
311  }
312 
313  QTextStream ts( &reportf );
314  write_report( ts );
315  reportf.close();
316 
317  // Write plots
318  write_plot( plot1File, data_plot1 );
319  write_plot( plot2File, data_plot2 );
320 
321  // Write moment data
322  QFile sm_data( textFile );
323  if ( ! sm_data.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
324  {
325  QMessageBox::warning( this,
326  tr( "IO Error" ),
327  tr( "Could not open\n" ) + textFile + "\n" +
328  tr( "\nfor writing" ) );
329  QApplication::restoreOverrideCursor();
330  return;
331  }
332 
333  const QString sep( "\",\"" );
334  const QString quo( "\"" );
335  const QString eln( "\"\n" );
336  QTextStream ts_data( &sm_data );
337 
338  int scanCount = d->scanData.size();
339  int excludes = le_skipped->text().toInt();
340 
341  if ( excludes == scanCount )
342  ts_data << "No valid scans\n";
343  else
344  {
345  ts_data << quo << "Count" << sep << "Points" << sep << "Seconds" << eln;
346  int count = 1;
347  for ( int i = excludes; i < scanCount; i++ )
348  {
349  if ( excludedScans.contains( i ) ) continue;
350 
351  QString strK = QString::number( count ).simplified();
352  QString strP = QString::number( smPoints [ i ], 'f', 5 ).simplified();
353  QString strS = QString::number( smSeconds[ i ], 'f', 5 ).simplified();
354  ts_data << quo << strK << sep << strP << sep << strS << eln;
355  count++;
356  }
357  }
358 
359  sm_data.close();
360  QStringList repfiles;
361  update_filelist( repfiles, htmlFile );
362  update_filelist( repfiles, plot1File );
363  update_filelist( repfiles, plot2File );
364  update_filelist( repfiles, textFile );
365  update_filelist( repfiles, dsinfFile );
366 
367  // Tell user
368  htmlFile = htmlFile .mid( htmlFile .lastIndexOf( "/" ) + 1 );
369  plot1File = plot1File.mid( plot1File.lastIndexOf( "/" ) + 1 );
370  plot2File = plot2File.mid( plot2File.lastIndexOf( "/" ) + 1 );
371  textFile = textFile .mid( textFile .lastIndexOf( "/" ) + 1 );
372  dsinfFile = dsinfFile.mid( dsinfFile.lastIndexOf( "/" ) + 1 );
373 
374  QString wmsg = tr( "Wrote:\n " ) + htmlFile + "\n "
375  + plot1File + "\n " + plot2File + "\n " + textFile + "\n "
376  + dsinfFile;
377 
378  if ( disk_controls->db() )
379  { // Write report files to the database
380  reportFilesToDB( repfiles );
381 
382  wmsg += tr( "\n\nReport files were also saved to the database." );
383  }
384 
385  QApplication::restoreOverrideCursor();
386  QMessageBox::warning( this, tr( "Success" ), wmsg );
387 }
388