13 QVector< US_DataIO::EditedData >& dataList,
14 QVector< ScanEdit >& scedits,
15 QVector< EqScanFit >& scanfits,
19 dataList ( dataList ),
21 scanfits ( scanfits ),
27 asters = QString().fill(
'*', 80 ).append(
"\n" );
33 DbgLv(1) <<
"SCAN_DIAGS()";
35 QString plsrd = tr(
"PLEASE READ THIS!" );
39 rs =
"\n" +
centerInLine( plsrd, 80,
false,
' ' ) +
"\n\n";
40 rs += tr(
"Below is a listing of the ratios of slopes in the endpoints"
41 " of each indicated\n" );
42 rs += tr(
"scan. If the ratios are less than 30, then there is little"
43 " information content\n" );
44 rs += tr(
"in the scan and chances are that the experiment was"
45 " improperly set up\nand should be repeated.\n\n" );
46 rs += tr(
"Additional warnings will be generated if the scan does not"
47 " contain enough\n" );
48 rs += tr(
"data points or if the experimenter did not use the majority"
50 rs += tr(
"absorbance range available (at least 0.6 OD between 0.0 OD"
51 " and 0.9 OD).\n\n" );
52 rs += tr(
"These warnings are for your information only; they have no"
54 rs += tr(
"rest of the program, since there are valid exceptions to"
55 " these warnings\n" );
56 rs += tr(
"when including such scans is appropriate. Please refer to"
58 rs += tr(
"equilibrium analysis tutorial for more information.\n\n" );
61 int dimvs =
dataList[ 0 ].pointCount() * 3 / 2;
62 QVector< double > xvec( dimvs );
63 QVector< double > yvec( dimvs );
64 double* xx = xvec.data();
65 double* yy = yvec.data();
68 for (
int jes = 0; jes <
scedits.size(); jes++ )
70 int jdx =
scedits[ jes ].dsindex;
71 double radlo =
scedits[ jes ].rad_lo;
72 double radhi =
scedits[ jes ].rad_hi;
82 ivenx =
min( ivenx, endx );
83 int ivenn = ivenx + 1;
84 int npts = ivenn - ivstx;
94 DbgLv(1) <<
"SDiag: jes" << jes <<
"ivstx ivenx npts" << ivstx << ivenx << npts;
95 DbgLv(1) <<
"SDiag: radlo radhi" << radlo << radhi
96 <<
" rs re" << sdata->
radius(ivstx) << sdata->
radius(ivenx)
103 int nspts = npts / 5;
111 for (
int jj = ivstx; jj < ivstx + nspts; jj++ )
113 xx[ knt ] =
scanfits[ jes ].xvs[ jj ];
114 yy[ knt++ ] =
scanfits[ jes ].yvs[ jj ];
119 DbgLv(1) <<
"SDiag: knt slope1 icept" << knt << slope1 << icept;
120 double xstart = xx[ 0 ];
121 double ystart = slope1 * xstart + icept;
126 for (
int jj = ivenn - nspts; jj < ivenn; jj++ )
128 xx[ knt ] =
scanfits[ jes ].xvs[ jj ];
129 yy[ knt++ ] =
scanfits[ jes ].yvs[ jj ];
134 double xend = xx[ knt - 1 ];
135 double yend = slope2 * xend + icept;
138 slope1 = ( slope1 == 0.0 ) ? 9.999999e-21 : slope1;
139 double ratio = slope2 / slope1;
140 double rangea = yend - ystart;
141 DbgLv(1) <<
"SDiag: knt slope2 icept" << knt << slope2 << icept;
142 DbgLv(1) <<
"SDiag: y0 y1 ym yn" << yy[0] << yy[1] << yy[knt-2] << yy[knt-1];
143 DbgLv(1) <<
"SDiag: xend yend" << xend << yend;
144 DbgLv(1) <<
"SDiag: ratio rangea" << ratio << rangea;
146 rs += tr(
"Slope at beginning: %1, Slope at end %2, "
147 "Ratio: %3\n\n" ).arg( slope1 ).arg( slope2 ).arg( ratio );
151 if ( ratio > 0.0 && ratio < 1.5 )
153 rs += tr(
"Warning: The ratio is very small - there is"
154 " probably not enough\n"
155 "information in this scan.\n"
156 "Suggestion: use a higher speed. Also, check"
157 " for aggregation!\n\n" );
163 rs += tr(
"Warning: The start point slope for this scan"
165 "Possible reasons: excessive noise in the data,"
166 " or time invariant noise\n"
167 "from interference data has not been subtracted.\n\n" );
173 rs += tr(
"Warning: The end point slope for this scan"
175 "Possible reasons: excessive noise in the data,"
176 " or time invariant noise\n"
177 "from interference data has not been subtracted.\n\n" );
183 rs += tr(
"Warning: This scan only spans %1 OD of the"
184 " possible\n" ). arg( rangea );
185 rs += tr(
"0.9 - 1.0 OD range the instrument allows.\n\n" );
191 rs += tr(
"Warning: This scan's maximum absorbance is only "
192 " %1 OD.\n" ).arg( yend );
193 rs += tr(
"This is lower than the linear range of the XL-A"
194 " which generally extends\n"
195 "up to ~0.9 OD. You may be discarding information."
196 " Check for Aggregation!\n\n" );
203 rs += tr(
"Number of points in this scan: %1" ).arg( npts );
211 rs += tr(
" (low!)\n\n" );
213 rs += tr(
" (too low! Are the data below the OD cutoff?)\n\n" );
218 rs += tr(
"There was 1 warning generated for this scan.\n" );
221 rs += tr(
"There were %1 warnings generated for this scan.\n" )
225 rs += tr(
"Please check the scan to make sure it is appropriate"
226 " for inclusion in a global fit!\n" );
246 QMessageBox::warning(
wparent, tr(
"Scan Problem(s)" ),
247 tr(
"One or more scans have been excluded from the fit.\n"
248 "The Diagnostics report will help you to determine\n"
249 "which problems occurred. You can manually override\n"
250 "scan exclusions and include them, once you identify\n"
251 "the reasons for the exclusion." ) );
258 ediag->setWindowTitle( tr(
"Scan Diagnostics" ) );
261 ediag->
e->setFont( efont );
262 ediag->
e->setText( rs );
263 QFontMetrics fm( efont );
265 DbgLv(1) <<
"dwid" << dwid;
266 int dhgt = fm.lineSpacing() * 50;
267 dwid = ( ( dwid / 12 + 2 ) * 12 );
268 dhgt = ( ( dhgt / 12 + 2 ) * 12 );
269 ediag->resize( dwid, dhgt );
270 ediag->move(
wparent->pos() + QPoint( 400, 100 ) );
275 QString repdir =
dataList[ 0 ].runID;
276 QDir folder( basedir );
278 if ( ! folder.exists( repdir ) )
280 if ( ! folder.mkdir( repdir ) )
282 QMessageBox::warning(
wparent, tr(
"File Error" ),
283 tr(
"Could not create the directory:\n" )
284 + basedir +
"/" + repdir );
289 QString filename = basedir +
"/" + repdir +
"/globeq.diagnostics.rpt";
290 QFile drf( filename );
292 if ( ! drf.open( QIODevice::WriteOnly | QIODevice::Text ) )
294 QMessageBox::warning(
wparent, tr(
"File Error" ),
295 tr(
"Unable to open the file:\n" ) + filename );
299 QTextStream ts( &drf );
307 DbgLv(1) <<
" EqRep:CHECK_SCAN_FIT()";
309 bool critical =
false;
314 DbgLv(1) <<
" EqRep:CSF: ffitx" << ffitx;
317 rs += tr(
"In order to assure that the proper parameters are used"
318 " for the fitting process,\n" );
319 rs += tr(
"the following information has been compiled about the"
320 " components in your\n" );
321 rs += tr(
"model and the scans included in the fit --\n\n"
322 "Component Information:\n\n" );
332 rs += tr(
"Although the molecular weight parameter for"
333 " component %1 has been floated,\n" ).arg( cnum );
334 rs += tr(
"the value for this parameter is equal to zero"
335 " - fitting aborted!\n" );
341 rs += tr(
"Although the molecular weight parameter for"
342 " component %1 has been floated,\n" ).arg( cnum );
343 rs += tr(
"the range for this parameter is equal to zero"
344 " - fitting aborted!\n" );
351 rs += tr(
"The molecular weight parameter for component %1"
352 " has been fixed.\n" ).arg( cnum );
359 rs += tr(
"Although the vbar parameter for"
360 " component %1 has been floated,\n" ).arg( cnum );
361 rs += tr(
"the value for this parameter is equal to zero"
362 " - fitting aborted!\n" );
368 rs += tr(
"Although the vbar parameter for"
369 " component %1 has been floated,\n" ).arg( cnum );
370 rs += tr(
"the range for this parameter is equal to zero"
371 " - fitting aborted!\n" );
378 rs += tr(
"The vbar parameter for component %1"
379 " has been fixed.\n" ).arg( cnum );
384 rs += tr(
"The vbar value for component %1 has been"
385 " left at 0.72,\n" ).arg( cnum );
386 rs += tr(
"which is the default value - are you sure"
387 " you want to use this value?\n" );
400 rs += tr(
"Although the equilibrium constant %1 has"
401 " been floated,\n" ).arg( anum );
402 rs += tr(
"the value for this parameter is equal to zero"
403 " - fitting aborted!\n" );
409 rs += tr(
"Although the equilibrium constant %1 has"
410 " been floated,\n" ).arg( anum );
411 rs += tr(
"the range for this parameter is equal to zero"
412 " - fitting aborted!\n" );
419 rs += tr(
"The equilibrium constant %1 has been fixed"
420 " - are you sure you want to do that?\n" ).arg( anum );
426 bool same_waveln =
true;
427 bool same_extinc =
true;
428 int test_waveln =
scanfits[ ffitx ].wavelen;
429 DbgLv(1) <<
" EqRep:CSF: fx extsz" << ffitx <<
scanfits[ffitx].extincts.size();
430 DbgLv(1) <<
" EqRep:CSF: test_waveln" << test_waveln;
431 double test_extinc =
scanfits[ ffitx ].extincts[ 0 ];
432 DbgLv(1) <<
" EqRep:CSF: test_extinc" << test_extinc;
434 for (
int jj = 0; jj <
scanfits.size(); jj++ )
438 if (
scanfits[ jj ].wavelen != test_waveln )
441 if (
scanfits[ jj ].extincts[ 0 ] != test_extinc )
446 if ( ! same_waveln && same_extinc )
447 rs += tr(
"\nWarning:\n"
448 "Your project contains scans with different wavelengths\n"
449 "but identical extinction coefficients!\n" );
451 else if ( ! same_waveln && ! same_extinc )
452 rs += tr(
"\nWarning:\n"
453 "Your project contains scans with different wavelengths;\n"
454 "make sure that the extinction coefficients match!\n" );
458 for (
int jes = 0; jes <
scedits.size(); jes++ )
460 int jdx =
scedits[ jes ].dsindex;
471 if (
scanfits[ jes ].amp_fits[ jj ] )
473 if (
scanfits[ jes ].amp_vals[ jj ] == 0.0 )
475 rs += tr(
"Although the amplitude for component %1 has"
476 " been floated,\nthe value for this parameter"
477 " is equal to zero - fitting aborted!\n" );
481 if (
scanfits[ jes ].amp_rngs[ jj ] == 0.0 )
483 rs += tr(
"Although the amplitude for component %1 has"
484 " been floated,\nthe range for this parameter"
485 " is equal to zero - fitting aborted!\n" );
493 rs += tr(
"The amplitude for component %1 has been fixed -"
494 " are you sure you want to do that?\n" ).arg( cnum );
499 if (
scanfits[ jes ].extincts[ jj ] == 0.0 )
501 rs += tr(
"The extinction coefficient for component %1 is"
502 " equal to zero - are you sure?\n" ).arg( cnum );
503 rs += tr(
"(This could be valid if this component does"
504 " not absort at %1 nm)\n" )
512 if (
scanfits[ jes ].baseln_rng == 0.0 )
514 rs += tr(
"Although the baseline for this scan has"
515 " been floated,\nthe range for this parameter"
516 " is equal to zero - fitting aborted!\n" );
523 rs += tr(
"The baseline for this scan has been fixed -"
524 " are you sure you want to do that?\n" );
527 if ( (
int)( 1000000.0 *
scanfits[ jes ].density + 0.5 ) == 998234 )
529 rs += tr(
"The density setting corresponds to pure water -"
530 " are you sure you want to use that?\n" );
538 rs += tr(
"This scan has been excluded from the fit.\n" );
545 ediag->setWindowTitle( tr(
"Scan Fit Check" ) );
548 ediag->
e->setFont( efont );
549 ediag->
e->setText( rs );
550 QFontMetrics fm( efont );
552 DbgLv(1) <<
" dwid" << dwid <<
" astw" << fm.width(
asters );
553 int dhgt = fm.lineSpacing() * 50;
554 dwid = ( ( dwid / 12 + 2 ) * 12 );
555 dhgt = ( ( dhgt / 12 + 2 ) * 12 );
556 DbgLv(1) <<
" dwid" << dwid;
557 ediag->resize( dwid, dhgt );
558 ediag->move(
wparent->pos() + QPoint( 450, 150 ) );
563 QString repdir =
dataList[ 0 ].runID;
564 QDir folder( basedir );
566 if ( ! folder.exists( repdir ) )
568 if ( ! folder.mkdir( repdir ) )
570 QMessageBox::warning(
wparent, tr(
"File Error" ),
571 tr(
"Could not create the directory:\n" )
572 + basedir +
"/" + repdir );
577 QString filename = basedir +
"/" + repdir +
"/globeq.scan_check.rpt";
578 QFile drf( filename );
580 if ( ! drf.open( QIODevice::WriteOnly | QIODevice::Text ) )
582 QMessageBox::warning(
wparent, tr(
"File Error" ),
583 tr(
"Unable to open the file:\n" ) + filename );
587 QTextStream ts( &drf );
596 bool wrreport, QString& filename )
599 DbgLv(1) <<
" EqRep:FIT_REPORT()";
600 QString mtitl = tr(
"Global Equilibrium Fit Analysis" );
601 QString fitd = tr(
" (fitted)" );
602 QString fixd = tr(
" (fixed) " );
606 rs += tr(
"Data Report for Project \"%1\"" ).arg(
runfit.
projname ) +
"\n";
608 rs += tr(
"Parameters for this model:" ) +
"\n\n";
612 rs += tr(
"For component %1:\n" ).arg( ii + 1 );
613 rs += tr(
" Molecular Weight" );
616 rs += tr(
" Partial Specific Volume" );
623 rs += tr(
" Association (Dissociation) Constant %1: %2" )
624 .arg( jj + 1 ).arg( eqval );
629 rs += tr(
"\nGlobal Fitting Statistics:\n\n" );
630 rs += tr(
"Variance: %1\n" )
632 rs += tr(
"Standard Deviation: %1\n" )
634 rs += tr(
"Number of floated Parameters: %1\n" )
636 rs += tr(
"Number of Datasets (scans): %1\n" )
638 rs += tr(
"Number of total Datapoints: %1\n" )
639 .arg( fitpars.
ntpts );
645 for (
int ii = 0; ii <
scanfits.size(); ii++ )
646 if (
scanfits[ ii ].scanFit ) niscns++;
648 double ptfac = (double)niscns / (
double)fitpars.
ntpts;
650 for (
int ii = 0; ii <
scanfits.size(); ii++ )
654 if ( ! scnf->
scanFit )
continue;
656 int jdax =
scedits[ ii ].dsindex;
657 int jscx =
scedits[ ii ].scannbr - 1;
659 double deltar =
dataList[ jdax ].scanData[ jscx ].delta_r;
660 double ptdens = (double)scnf->
points * ptfac;
661 double dpscale = deltar / ptdens;
662 totneg += ( (
double)scnf->
nbr_negr * dpscale );
663 totpos += ( (double)scnf->
nbr_posr * dpscale );
666 double totprod = totneg * totpos;
667 double totsum = totneg + totpos;
668 double totprod2 = 2.0 * totprod;
673 / (
sq( totprod ) * ( totsum - 1.0 ) );
675 rs += tr(
"Average Datapoint concentration: Not determined\n" );
676 rs += tr(
"Number of Degrees of Freedom: %1\n" )
678 rs += tr(
"Number of Runs (corrected): %1 (%2 %)\n" )
680 rs += tr(
"Expected Number of Runs (corrected): %1\n" )
682 rs += tr(
"Run Variance (corrected): %1\n" )
685 rs += tr(
"\nAccording to these statistical tests, this model is " );
690 rs += tr(
"either inappropriate for\n" );
693 rs += tr(
"either a poor candidate for\n" );
695 rs += tr(
"the experimental data, or the fitting process has not yet"
696 " converged. Please try to reduce\n" );
697 rs += tr(
"the variance by additional nonlinear least-squares"
698 " minimization of the data.\n" );
699 rs += tr(
"This fit cannot be used for a Monte Carlo Analysis.\n" );
704 rs += tr(
"an acceptable candidate for\nthe experimental data.\n" );
705 rs += tr(
"This fit can be used for a Monte Carlo Analysis"
706 " with reservations.\n" );
711 rs += tr(
"a good candidate for\nthe experimental data.\n" );
712 rs += tr(
"This fit is recommended for Monte Carlo Analysis.\n" );
715 rs += tr(
"\nDetailed Information for fitted Scans:\n" );
717 for (
int ii = 0; ii <
scanfits.size(); ii++ )
726 rs += tr(
"This scan has been excluded from the Fit.\n" );
730 rs += tr(
"Baseline" );
732 rs += QString(
": %1 OD\n" )
734 rs += tr(
"Meniscus: %1\n" )
736 rs += tr(
"Bottom: %1\n" )
738 double tempera = scnf->
tempera;
739 double density = scnf->
density;
740 rs += tr(
"Density setting: %1 g/ccm\n" )
742 rs += tr(
"Temperature setting: %1" )
743 .arg( tempera ) +
DEGC +
"\n";
748 rs += tr(
" Amplitude of component %1" ).arg( compn );
749 rs += scnf->
amp_fits[ jj ] ? fitd : fixd;
750 rs += QString(
": %1 OD\n" ).arg( scnf->
amp_vals[ jj ] );
751 rs += tr(
" Integral of component: %2\n" )
753 rs += tr(
" Extinction Coefficient of component: %2\n" )
757 double buoy = ( 1.0 - vbar20 * density );
758 rs += tr(
" Partial Specific Volume of component: %2 (20W)\n" )
760 rs += tr(
" Buoyancy (20W) of component: %2\n" )
764 rs += tr(
"Pathlength: %1 cm\n" )
766 rs += tr(
"\nFitting Statistics for this Scan:\n" );
767 rs += tr(
"Number of Runs (corrected): %1\n" )
771 double runpro2 = runprod * 2.0;
772 double expectr = 1.0 + runpro2 / runsum;
773 double varirun = ( runpro2 * ( runpro2 - runsum ) )
774 / (
sq( runsum ) * ( runsum - 1.0 ) );
775 rs += tr(
"Expected Number of Runs (corrected): %1\n" )
776 .arg( qRound( expectr ) );
777 rs += tr(
"Run Variance (corrected): %1\n" )
785 ediag->setWindowTitle( mtitl );
788 ediag->
e->setFont( efont );
789 ediag->
e->setText( rs );
790 QFontMetrics fm( efont );
792 int dhgt = fm.lineSpacing() * 50;
793 dwid = ( ( dwid / 12 + 2 ) * 12 );
794 dhgt = ( ( dhgt / 12 + 2 ) * 12 );
795 ediag->resize( dwid, dhgt );
796 ediag->move(
wparent->pos() + QPoint( 400, 100 ) );
804 QFile drf( filename );
806 if ( ! drf.open( QIODevice::WriteOnly | QIODevice::Text ) )
808 QMessageBox::warning(
wparent, tr(
"File Error" ),
809 tr(
"Unable to open the file:\n" ) + filename );
814 QTextStream ts( &drf );
829 while ( ++r_index < l_index )
831 if ( radius <= edat->radius( r_index ) )
840 bool rightPad,
const QChar end_char )
842 int tlen = titl_text.length();
843 int plen = ( linelen - tlen ) / 2;
844 bool have_end = ( ! end_char.isNull() && end_char !=
' ' );
847 QString linestr = QString().fill(
' ', plen ) + titl_text;
851 plen = linelen - tlen - plen;
852 linestr += QString().fill(
' ', plen );
856 linestr.replace( linestr.length() - 1, 1, end_char );
861 linestr.replace( 0, 1, end_char );
870 + tr(
"Information for Scan " ) + QString::number( jes + 1 )
871 + tr(
", Cell " ) +
dataList[ jdx ].cell
872 + tr(
", Channel " ) +
dataList[ jdx ].channel
873 + tr(
", Wavelength " ) +
dataList[ jdx ].wavelength
874 +
" nm, " + QString::number(
scanfits[ jes ].rpm ) + tr(
" rpm" )
881 QStringList rlines = repstr.split(
"\n" );
885 for (
int ii = 0; ii < rlines.size(); ii++ )
887 if ( ( lnlen = fm.width( rlines[ ii ] ) ) > mxlen )
890 DbgLv(1) <<
" mLW: ii lnlen" << ii << lnlen <<
" line:" << rlines[ii];