UltraScan III
us_2dsa_process.cpp
Go to the documentation of this file.
1 
3 #include "us_2dsa.h"
4 #include "us_2dsa_process.h"
5 #include "us_util.h"
6 #include "us_settings.h"
7 #include "us_astfem_math.h"
8 #include "us_astfem_rsa.h"
9 #include "us_sleep.h"
10 #include "us_math2.h"
11 #include "us_constants.h"
12 #include "us_memory.h"
13 
14 // Class to process 2DSA simulations
15 US_2dsaProcess::US_2dsaProcess( QList< SS_DATASET* >& dsets,
16  QObject* parent /*=0*/ ) : QObject( parent ), dsets( dsets )
17 {
18  bdata = &dsets[ 0 ]->run_data; // pointer to base experiment data
19  edata = bdata; // working pointer to experiment
20  parentw = parent;
22  maxrss = 0; // max memory
23  maxdepth = 0; // maximum depth index of tasks
24  ntisols = 0; // number total task input solutes
25  ntcsols = 0; // number total task computed solutes
26  varitol = 1e-12; // variance difference tolerance
27  r_iter = 0; // refinement iteration index
28  mm_iter = 0; // meniscus/MC iteration index
29  //mintsols = 100; // minimum solutes per task, depth 1 ff.
30  mintsols = 40; // minimum solutes per task, depth 1 ff.
31  maxiters = 1; // maximum refinement iterations
32  mmtype = 0; // meniscus/montecarlo type (NONE)
33  mmiters = 0; // meniscus/montecarlo iterations
34  fnoionly = US_Settings::debug_match( "2dsaFinalNoiseOnly" );
35 
36  itvaris .clear(); // iteration variances
37  ical_sols.clear(); // iteration final calculated solutes
38  simparms = &dsets[ 0 ]->simparams; // pointer to simulation parameters
39 
40  nscans = bdata->scanCount();
42 
43  if ( ( nscans * npoints ) > 50000 )
44  //mintsols = 80;
45  mintsols = 20;
46 }
47 
48 // Get maximum used memory
49 long int US_2dsaProcess::max_rss( void )
50 {
51  return US_Memory::rss_max( maxrss );
52 }
53 
54 // Start a specified 2DSA fit run
55 void US_2dsaProcess::start_fit( double sll, double sul, int nss,
56  double kll, double kul, int nks,
57  int ngr, int nthr, int noif )
58 {
59 DbgLv(1) << "2P(2dsaProc): start_fit()";
60  abort = false;
61  slolim = sll;
62  suplim = sul;
63  nssteps = nss;
64  klolim = kll;
65  kuplim = kul;
66  nksteps = nks;
67  jgrefine = ngr;
68  ngrefine = ngr;
69  nthreads = nthr;
70  noisflag = noif;
71  errMsg = tr( "NO ERROR: start" );
72  maxrss = 0;
73  maxdepth = 0;
74  ntisols = 0;
75  ntcsols = 0;
76  r_iter = 0;
77  mm_iter = 0;
78 
79  if ( jgrefine < 0 )
80  { // Special model-grid or model-ratio grid refinement
81  ngrefine = 1;
82  model = dsets[ 0 ]->model;
83  slolim = model.components[ 0 ].s * 1.0e+13;
84  klolim = model.components[ 0 ].f_f0;
85  nksteps = model.components.size();
86  int kk = qMax( 1, nksteps ) - 1;
87  suplim = model.components[ kk ].s * 1.0e+13;
88  kuplim = model.components[ kk ].f_f0;
89  nssteps = qMax( 1, nssteps );
90  nssteps = (int)sqrt( (double)nksteps );
91  nssteps = qMax( 1, nssteps );
93  nksteps = qMax( 1, nksteps );
94  }
95 
96  wkstates .resize( nthreads );
97  wkdepths .resize( nthreads );
98  wthreads .clear();
99  tkdepths .clear();
100  job_queue.clear();
101  c_solutes.clear();
102 
103  orig_sols.clear();
104  itvaris .clear();
105  ical_sols.clear();
106 
107 DbgLv(1) << "2P: sll sul nss" << slolim << suplim << nssteps
108  << " kll kul nks" << klolim << kuplim << nksteps
109  << " ngref nthr noif" << ngrefine << nthreads << noisflag;
110 
111  timer.start(); // start a timer to measure run time
112 
113  edata = bdata; // initial iteration base experiment data
114 
115  if ( mmtype > 0 )
116  { // for meniscus or monte carlo, make a working copy of the base data
117  wdata = *bdata;
118 
119  if ( mmtype == 1 )
120  { // if meniscus, use the start meniscus value
121  edata = &wdata;
122  double bmeniscus = bdata->meniscus;
123  edata->meniscus = bmeniscus - menrange * 0.5;
124  dsets[ 0 ]->simparams.meniscus = edata->meniscus;
125 DbgLv(1) << "MENISC: mm_iter meniscus bmeniscus"
126  << mm_iter << edata->meniscus << bmeniscus;
127  }
128  }
129 
130  // experiment data dimensions
131  nscans = edata->scanCount();
132  npoints = edata->pointCount();
133 
134  // SubGrid deltas (increments between subgrid points)
135  int nsubp_s = ( nssteps + ngrefine - 1 ) / ngrefine;
136  int nsubp_k = ( nksteps + ngrefine - 1 ) / ngrefine;
137  sdelta_s = ( suplim - slolim ) / (double)( qMax( nsubp_s - 1, 1 ) );
138  sdelta_k = ( kuplim - klolim ) / (double)( qMax( nsubp_k - 1, 1 ) );
139 
140  // Grid deltas (overall increment between grid points)
141  gdelta_s = sdelta_s / (double)ngrefine;
142  gdelta_k = sdelta_k / (double)ngrefine;
143  if ( jgrefine > 0 )
144  {
145  nsubgrid = sq( ngrefine );
146  maxtsols = nsubp_s * nsubp_k;
147  }
148  else
149  {
151  maxtsols = model.components.size() / nsubgrid;
152  }
153  int kgref = ngrefine - 1;
154  int kgrefsq = sq( kgref );
155  int kksubg = nksteps * nssteps
156  - ( kgref + kgrefsq ) * ( nsubp_s + nsubp_k ) + kgrefsq;
157 DbgLv(1) << "2P: kgref kgrefsq kksubg" << kgref << kgrefsq << kksubg;
158  maxtsols = qMax( maxtsols, mintsols );
159 
160  int ktcsol = maxtsols - 5;
161  int nnstep = ( noisflag > 0 ? ( sq( ktcsol ) / 10 + 2 ) : 2 ) * nsubgrid;
162  nctotal = kksubg + nnstep + estimate_steps( ( kksubg / 8 ) );
163 
164  kcsteps = 0;
165  emit stage_complete( kcsteps, nctotal );
166  kctask = 0;
167  kstask = 0;
169 DbgLv(1) << "2P: nscans npoints" << nscans << npoints;
170 DbgLv(1) << "2P: gdelta_s gdelta_k" << gdelta_s << gdelta_k
171  << " sdelta_s sdelta_k" << sdelta_s << sdelta_k;
172 DbgLv(1) << "2P: nsubgrid nctotal nthreads maxtsols"
173  << nsubgrid << nctotal << nthreads << maxtsols;
174  max_rss();
175 DbgLv(1) << "2P: (1)maxrss" << maxrss << "jgrefine" << jgrefine;
176 
177  int jdpth = 0;
178  int jnois = fnoionly ? 0 : noisflag;
179  QList< QVector< US_Solute > > solute_list;
180  double ssllim = slolim * 1.0e-13;
181  double ssulim = suplim * 1.0e-13;
182  int ncomps = model.components.size();
183  double vbar20 = dsets[ 0 ]->vbar20;
184 
185  // Generate the original sub-grid solutes list
186  if ( jgrefine > 0 )
187  {
188  US_Solute::init_solutes( ssllim, ssulim, nssteps,
191 
192  for ( int ii = 0; ii < orig_sols.count(); ii++ )
193  for ( int jj = 0; jj < orig_sols[ ii ].count(); jj++ )
194  orig_sols[ ii ][ jj ].v = vbar20;
195  }
196 
197  else if ( jgrefine == (-1) )
198  { // model-grid
199  QVector< US_Solute > solvec;
200 
202  {
203  for ( int ii = 0; ii < nsubgrid; ii++ )
204  {
205  solvec.clear();
206 
207  for ( int jj = ii; jj < ncomps; jj += nsubgrid )
208  {
209  US_Solute soli( model.components[ jj ].s,
210  model.components[ jj ].f_f0,
211  0.0,
212  model.components[ jj ].vbar20,
213  model.components[ jj ].D );
214 DbgLv(1) << "ii" << ii << "soli" << soli.s << soli.k << soli.c << soli.v;
215  solvec << soli;
216  }
217 
218  orig_sols << solvec;
219  }
220  }
221 
222  else
223  {
224  for ( int ii = 0; ii < ncomps; ii++ )
225  {
226  US_Solute soli( model.components[ ii ].s,
227  model.components[ ii ].f_f0,
228  0.0,
229  model.components[ ii ].vbar20,
230  model.components[ ii ].D );
231 DbgLv(1) << "ii" << ii << "soli" << soli.s << soli.k << soli.c;
232  solvec << soli;
233  }
234 
235  orig_sols << solvec;
236  }
237  }
238 
239  else if ( jgrefine == (-2) )
240  { // model-ratio
241  QVector< US_Solute > solvec;
242 
243  for ( int ii = 0; ii < ncomps; ii++ )
244  {
245  US_Solute soli( model.components[ ii ].s,
246  model.components[ ii ].f_f0,
247  model.components[ ii ].signal_concentration,
248  model.components[ ii ].vbar20,
249  model.components[ ii ].D );
250 DbgLv(1) << "ii" << ii << "soli" << soli.s << soli.k << soli.c;
251  solvec << soli;
252  }
253 
254  orig_sols << solvec;
255  }
256 
257  // Queue all the depth-0 tasks
258  for ( int ktask = 0; ktask < nsubgrid; ktask++ )
259  {
260  WorkPacket2D wtask;
261  double llss = orig_sols[ ktask ][ 0 ].s;
262  double llsk = orig_sols[ ktask ][ 0 ].k;
263 
264  queue_task( wtask, llss, llsk, ktask, jdpth, jnois, orig_sols[ ktask ] );
265 
266  maxtsols = qMax( maxtsols, wtask.isolutes.size() );
267  }
268 
269  // Start the first threads. This will begin the first work units (subgrids).
270  // Thereafter, work units are started in new threads when previous
271  // threads signal that they have completed their work.
272 
273  for ( int ii = 0; ii < nthreads; ii++ )
274  {
275  wthreads << 0;
276 
277  WorkPacket2D wtask = job_queue.takeFirst();
278  submit_job( wtask, ii );
279 
280 // memory_check();
281  }
282 
283  max_rss();
284  kstask = nthreads; // count of started tasks is initially thread count
285 DbgLv(1) << "2P: kstask nthreads" << kstask << nthreads << job_queue.size();
286 
287  emit message_update( pmessage_head() +
288  tr( "Starting computations of %1 subgrids\n using %2 threads ..." )
289  .arg( nsubgrid ).arg( nthreads ), false );
290 
291  memory_check();
292 }
293 
294 // Set iteration parameters
295 void US_2dsaProcess::set_iters( int mxiter, int mciter, int mniter,
296  double vtoler, double menrng, double cff0,
297  int jgref )
298 {
299  maxiters = mxiter;
300  mmtype = ( mciter > 1 ) ? 2 : ( ( mniter > 1 ) ? 1 : 0 );
301  mmiters = ( mmtype == 0 ) ? 0 : qMax( mciter, mniter );
302  varitol = vtoler;
303  menrange = menrng;
304  cnstff0 = cff0;
305  jgrefine = jgref;
306 
307  int stype = 0; // Constant vbar, varying f/f0
308  if ( jgrefine > 0 )
309  {
310  if ( cnstff0 > 0.0 )
311  stype = 1; // Constant f/f0, varying vbar
312  }
313  else
314  stype = 2; // Custom grid
315 
316  dsets[ 0 ]->solute_type = stype; // Store solute type
317 DbgLv(1) << "2PSI: cnstff0 jgrefine stype" << cnstff0 << jgrefine << stype;
318 }
319 
320 // Abort a fit run
322 {
323  abort = true;
324 
325  for ( int ii = 0; ii < wthreads.size(); ii++ )
326  {
327 DbgLv(1) << "StopFit test Thread" << ii + 1;
328  WorkerThread2D* wthr = wthreads[ ii ];
329 
330  if ( wthr != 0 )
331  {
332  wthr->disconnect();
333 
334  if ( wthr->isRunning() )
335  {
336  wthr->flag_abort();
337 DbgLv(1) << " STOPTHR: thread aborted";
338  US_Sleep::msleep( 500 );
339  }
340 
341  delete wthr;
342 DbgLv(1) << " STOPTHR: thread deleted";
343  }
344 
345  wthreads[ ii ] = 0;
346  }
347 
348  job_queue.clear();
349  tkdepths .clear();
350  c_solutes.clear();
351  maxdepth = 0;
352  ntisols = 0;
353  ntcsols = 0;
354 
355  emit message_update( pmessage_head() +
356  tr( "All computations have been aborted." ), false );
357 }
358 
359 // Clear the processor data vector and list memory
361 {
362  sigmas .clear();
363  itvaris .clear();
364  c_solutes.clear();
365  orig_sols.clear();
366  ical_sols.clear();
367  wdata .scanData.clear();
368  sdata .scanData.clear();
369  sdata1.scanData.clear();
370  rdata .scanData.clear();
371 }
372 
373 // Slot for thread step progress: signal control progress bar
375 {
376  max_rss();
377  kcsteps += ksteps; // bump completed steps count
378 //DbgLv(2) << "StpPr: ks kcs " << ksteps << kcsteps;
379 
380  emit progress_update( ksteps ); // pass progress on to control window
381 }
382 
383 // Use a worker thread one last time to compute, using all computed solutes
385 {
386  if ( abort ) return;
387 
388  max_rss();
389 
390  WorkPacket2D wtask;
391 
392  int depth = maxdepth++;
393  wtask.thrn = 0;
394  wtask.taskx = tkdepths.size();
395  wtask.depth = maxdepth;
396  wtask.noisf = noisflag; // in this case, we use the noise flag
397  wtask.dsets = dsets;
398  wtask.csolutes.clear();
399  wtask.ti_noise.clear();
400  wtask.ri_noise.clear();
401 
402  tkdepths << wtask.depth;
403 
404  // This time, input solutes are all the subgrid-computed ones where
405  // the concentration is positive.
406  qSort( c_solutes[ depth ] );
407 DbgLv(1) << "FinalComp: szSoluC" << c_solutes[ depth ].size();
408  wtask.isolutes.clear();
409 
410  for ( int ii = 0; ii < c_solutes[ depth ].size(); ii++ )
411  {
412  if ( c_solutes[ depth ][ ii ].c > 0.0 )
413  wtask.isolutes << c_solutes[ depth ][ ii ];
414  }
415 DbgLv(1) << "FinalComp: szSoluI" << wtask.isolutes.size();
416 
417  c_solutes[ depth ].clear();
418 
419  WorkerThread2D* wthr = new WorkerThread2D( this );
420 
421  int thrx = wkstates.indexOf( READY );
422  while ( thrx < 0 )
423  {
424  US_Sleep::msleep( 1 );
425  thrx = wkstates.indexOf( READY );
426  }
427 
428  wtask.thrn = thrx + 1;
429  wthr->define_work( wtask );
430 
431  connect( wthr, SIGNAL( work_complete( WorkerThread2D* ) ),
432  this, SLOT( process_final( WorkerThread2D* ) ) );
433  connect( wthr, SIGNAL( work_progress( int ) ),
434  this, SLOT( step_progress( int ) ) );
435 
436  emit message_update( pmessage_head() + tr( "Computing final NNLS ..." ),
437  false );
438 
439  wthreads[ thrx ] = wthr;
440  wthr->start( );
441 }
442 
443 // Slot to handle output of final pass on composite calculated solutes
445 {
446  if ( abort ) return;
447 
448  WorkPacket2D wresult;
449 
450  wthrd->get_result( wresult ); // get results of thread task
451 
452  if ( c_solutes.size() < ( maxdepth + 1 ) )
453  c_solutes << QVector< US_Solute >();
454 
455  c_solutes[ maxdepth ] = wresult.csolutes; // final iter calc'd solutes
456  int nsolutes = c_solutes[ maxdepth ].size();
457 
458  QVector< double > tinvec( npoints, 0.0 );
459  QVector< double > rinvec( nscans, 0.0 );
460 
461  if ( ( noisflag & 1 ) != 0 )
462  { // copy TI noise to caller and internal vector
463  ti_noise.minradius = edata->radius( 0 );
465  ti_noise.minradius = (double)qRound( ti_noise.minradius * 1e+5 ) * 1e-5;
466  ti_noise.maxradius = (double)qRound( ti_noise.maxradius * 1e+5 ) * 1e-5;
467  ti_noise.values.resize( npoints );
469 
470  for ( int rr = 0; rr < npoints; rr++ )
471  {
472  ti_noise.values[ rr ] = wresult.ti_noise[ rr ];
473  tinvec [ rr ] = wresult.ti_noise[ rr ];
474  }
475  }
476 
477  if ( ( noisflag & 2 ) != 0 )
478  { // copy RI noise to caller and internal vector
479  ri_noise.values.resize( nscans );
481 
482  for ( int ss = 0; ss < nscans; ss++ )
483  {
484  ri_noise.values[ ss ] = wresult.ri_noise[ ss ];
485  rinvec [ ss ] = wresult.ri_noise[ ss ];
486  }
487  }
488 DbgLv(1) << "FIN_FIN: ti,ri counts" << ti_noise.count << ri_noise.count;
489 
490  SS_DATASET* dset = dsets[ 0 ];
491  double sfactor = 1.0 / dset->s20w_correction;
492  double dfactor = 1.0 / dset->D20w_correction;
493  double vbar20 = dset->vbar20;
494 DbgLv(1) << "FIN_FIN: s20w,D20w_corr" << dset->s20w_correction
495  << dset->D20w_correction << "sfac dfac" << sfactor << dfactor;
496  model.components.resize( nsolutes );
497  qSort( c_solutes[ maxdepth ] );
498  //double bf_mult = simparms->band_forming
499  // ? simparms->cp_width
500  // : 1.0;
501 
502  // build the final model
503 
504  if ( dset->solute_type == 0 )
505  { // Normal case of varying f/f0
506  for ( int cc = 0; cc < nsolutes; cc++ )
507  {
508  // Get standard-space solute values (20,W)
510  mcomp.vbar20 = vbar20;
511  mcomp.s = c_solutes[ maxdepth ][ cc ].s;
512  mcomp.D = 0.0;
513  mcomp.mw = 0.0;
514  mcomp.f = 0.0;
515  mcomp.f_f0 = c_solutes[ maxdepth ][ cc ].k;
516  //mcomp.signal_concentration
517  // = c_solutes[ maxdepth ][ cc ].c * bf_mult;
519  = c_solutes[ maxdepth ][ cc ].c;
520 
521  // Complete other coefficients in standard-space
522  model.calc_coefficients( mcomp );
523 DbgLv(1) << " Bcc comp D" << mcomp.D;
524 
525  // Convert to experiment-space for simulation below
526  mcomp.s *= sfactor;
527  mcomp.D *= dfactor;
528 DbgLv(1) << " Bcc 20w comp D" << mcomp.D;
529 
530  model.components[ cc ] = mcomp;
531  }
532  } // Constant vbar
533 
534  else if ( dset->solute_type == 1 )
535  { // Special case of varying vbar
537  sd.viscosity = dset->viscosity;
538  sd.density = dset->density;
539  sd.manual = dset->manual;
540  double avtemp = dset->temperature;
541 
542  for ( int cc = 0; cc < nsolutes; cc++ )
543  {
544  // Get standard-space solute values (20,W)
546  mcomp.vbar20 = c_solutes[ maxdepth ][ cc ].v;
547  mcomp.s = c_solutes[ maxdepth ][ cc ].s;
548  mcomp.D = 0.0;
549  mcomp.mw = 0.0;
550  mcomp.f = 0.0;
551  mcomp.f_f0 = cnstff0;
553  = c_solutes[ maxdepth ][ cc ].c;
554 
555  // Complete other coefficients in standard-space
556  model.calc_coefficients( mcomp );
557 DbgLv(1) << " Bcc comp D" << mcomp.D;
558 
559  // Convert to experiment-space for simulation below
560  sd.vbar20 = mcomp.vbar20;
561  sd.vbar = US_Math2::adjust_vbar20( sd.vbar20, avtemp );
562  US_Math2::data_correction( avtemp, sd );
563 
564  mcomp.s /= sd.s20w_correction;
565  mcomp.D /= sd.D20w_correction;
566 DbgLv(1) << " Bcc 20w comp D" << mcomp.D;
567 
568  model.components[ cc ] = mcomp;
569  }
570  } // Constant f/f0
571 
572  else
573  { // Input was a custom grid
575  sd.viscosity = dset->viscosity;
576  sd.density = dset->density;
577  sd.manual = dset->manual;
578  double avtemp = dset->temperature;
579 
580  for ( int cc = 0; cc < nsolutes; cc++ )
581  {
582  // Get standard-space solute values (20,W)
584  mcomp.s = c_solutes[ maxdepth ][ cc ].s;
585  mcomp.D = c_solutes[ maxdepth ][ cc ].d;
586  mcomp.mw = 0.0;
587  mcomp.f = 0.0;
588  mcomp.f_f0 = 0.0;
589  mcomp.vbar20 = c_solutes[ maxdepth ][ cc ].v;
591  = c_solutes[ maxdepth ][ cc ].c;
592 
593  // Complete other coefficients in standard-space
594  model.calc_coefficients( mcomp );
595 DbgLv(1) << " Bcc comp D" << mcomp.D;
596 
597  // Convert to experiment-space for simulation below
598  sd.vbar20 = mcomp.vbar20;
599  sd.vbar = US_Math2::adjust_vbar20( sd.vbar20, avtemp );
600  US_Math2::data_correction( avtemp, sd );
601 
602  mcomp.s /= sd.s20w_correction;
603  mcomp.D /= sd.D20w_correction;
604 DbgLv(1) << " Bcc 20w comp D" << mcomp.D;
605 
606  model.components[ cc ] = mcomp;
607  }
608  } // Custom grid
609 
610 DbgLv(1) << "FIN_FIN: c0 cn" << c_solutes[maxdepth][0].c
611  << c_solutes[maxdepth][qMax(0,nsolutes-1)].c << " nsols" << nsolutes;
612  nscans = edata->scanCount();
613  npoints = edata->pointCount();
614  double vari = wresult.sim_vals.variances[ 0 ];
615 DbgLv(1) << "FIN_FIN: vari" << vari;
618  US_DataIO::RawData* simdat = &wresult.sim_vals.sim_data;
619  US_DataIO::RawData* resids = &wresult.sim_vals.residuals;
620 
621  // build residuals data set (experiment minus simulation minus any noise)
622  for ( int ss = 0; ss < nscans; ss++ )
623  {
624  for ( int rr = 0; rr < npoints; rr++ )
625  {
626  sdata.setValue( ss, rr, simdat->value( ss, rr ) );
627  rdata.setValue( ss, rr, resids->value( ss, rr ) );
628  }
629  }
630 
631 int mms=nscans/2;
632 int mmr=npoints/2;
633 DbgLv(1) << "FIN_FIN: edatm sdatm rdatm" << edata->value(mms,mmr)
634  << sdata.value(mms,mmr) << rdata.value(mms,mmr);
635 
636  // set variance and communicate to control through residual's scan 0
637  itvaris << vari;
638  ical_sols << c_solutes[ maxdepth ];
639  US_DataIO::Scan* rscan0 = &rdata.scanData[ 0 ];
640  rscan0->delta_r = vari;
641  rscan0->rpm = (double)( r_iter + 1 );
642  rscan0->seconds = ( mmtype == 0 ) ? 0.0 : (double)( mm_iter + 1 );
643  rscan0->plateau = ( mmtype != 1 ) ? 0.0 : edata->meniscus;
644 DbgLv(1) << "FIN_FIN: vari riter miter menisc" << rscan0->delta_r
645  << rscan0->rpm << rscan0->seconds << rscan0->plateau;
646 
647  // determine elapsed time
648  int ktimes = ( timer.elapsed() + 500 ) / 1000;
649  int ktimeh = ktimes / 3600;
650  int ktimem = ( ktimes - ktimeh * 3600 ) / 60;
651 double bvol = dsets[0]->simparams.band_volume;
652 bvol=dsets[0]->simparams.band_forming?bvol:0.0;
653 DbgLv(1) << "done: vari bvol" << vari << bvol
654  << "slun klun ngr" << slolim << suplim << nssteps << klolim << kuplim
655  << nksteps << ngrefine << "ets" << ktimes;
656  ktimes = ktimes - ktimeh * 3600 - ktimem * 60;
657 
658  // compose final iteration status message
659  QString pmsg = pmessage_head() +
660  tr( "The Solution has converged...\n"
661  "Iterations: %1\n"
662  "Threads: %2 ; Subgrids: %3\n"
663  "Grid points (s x f/f0): %4 x %5\n"
664  "Run time: " )
665  .arg( r_iter + 1 )
666  .arg( nthreads ).arg( nsubgrid ).arg( nssteps ).arg( nksteps );
667 
668  if ( ktimeh > 0 )
669  pmsg += tr( "%1 hr., %2 min., %3 sec.\n" )
670  .arg( ktimeh ).arg( ktimem ).arg( ktimes );
671 
672  else
673  pmsg += tr( "%1 min., %2 sec.\n" )
674  .arg( ktimem ).arg( ktimes );
675 
676  max_rss();
677  double memmb = (double)maxrss / 1024.0;
678 
679  pmsg += tr( "Maximum memory used: " )
680  + QString::number( qRound( memmb ) ) + " MB";
681 
682  emit message_update( pmsg, false ); // signal final message
683 
684  int thrx = wresult.thrn - 1;
685  free_worker( thrx );
686 DbgLv(1) << "FIN_FIN: Run Time: hr min sec" << ktimeh << ktimem << ktimes;
687 DbgLv(1) << "FIN_FIN: maxrss memmb nthr" << maxrss << memmb << nthreads
688  << " nsubg nsst nkst noisf" << nsubgrid << nssteps << nksteps << noisflag;
689 DbgLv(1) << "FIN_FIN: kcsteps nctotal" << kcsteps << nctotal;
690 
691  bool neediter = false; // need-more-iterations false by default
692 
693  if ( ( r_iter + 1 ) < maxiters )
694  { // possibly iterate if not yet at maximum iterations
695 
696  if ( r_iter < 1 )
697  { // if max not 2 or more, we must do at least 2 iterations to compare
698  neediter = true;
699  }
700 
701  else
702  { // otherwise, we must compare solutes and variance difference
703  int jc = r_iter;
704  int jp = r_iter - 1;
705  double pvari = itvaris[ jp ];
706  double dvari = fabs( pvari - vari );
707  int nccsol = ical_sols[ jc ].size();
708  int npcsol = ical_sols[ jp ].size();
709  bool sdiffs = true;
710 
711  if ( nccsol == npcsol )
712  { // determine if calculated solutes match previous in s and k
713  sdiffs = false;
714  for ( int jj = 0; jj < nccsol; jj++ )
715  {
716  if ( ical_sols[ jc ][ jj ] != ical_sols[ jp ][ jj ] )
717  { // if any mismatch, we may need to iterate
718  sdiffs = true;
719  break;
720  }
721  }
722  }
723 
724  // iterate if solutes different and variance change large enough
725  neediter = ( sdiffs && dvari > varitol );
726 DbgLv(1) << "FIN_FIN: neediter" << neediter << " sdiffs" << sdiffs
727  << " dvari varitol" << dvari << varitol << " iter" << r_iter;
728  }
729  }
730 
731  if ( neediter )
732  { // we must iterate
733  emit process_complete( 0 ); // signal that iteration is complete
734  iterate(); // reset to run another iteration
735  return;
736  }
737 
738  // Convert model components s,D back to 20,w form for output
739  if ( dset->solute_type == 0 )
740  { // Constant vbar
741  for ( int cc = 0; cc < nsolutes; cc++ )
742  {
743 DbgLv(1) << "cc comp D" << model.components[ cc ].D;
744  model.components[ cc ].s *= dset->s20w_correction;
745  model.components[ cc ].D *= dset->D20w_correction;
746 DbgLv(1) << " cc 20w comp D" << model.components[ cc ].D;
747  }
748  }
749  else
750  { // Varying vbar or custom
752  sd.viscosity = dset->viscosity;
753  sd.density = dset->density;
754  double avtemp = dset->temperature;
755 
756  for ( int cc = 0; cc < nsolutes; cc++ )
757  {
758  sd.vbar20 = model.components[ cc ].vbar20;
759  sd.vbar = US_Math2::adjust_vbar20( sd.vbar20, avtemp );
760  US_Math2::data_correction( avtemp, sd );
761 
762  model.components[ cc ].s *= sd.s20w_correction;
763  model.components[ cc ].D *= sd.D20w_correction;
764  }
765  }
766 
767  // Done with refinement iterations: check for meniscus or MC iteration
768 
769  if ( mmtype > 0 && ++mm_iter < mmiters )
770  { // doing meniscus or monte carlo and more to do
771  emit process_complete( mmtype ); // signal that iteration is complete
772 
773  if ( mmtype == 1 )
774  set_meniscus();
775 
776  else if ( mmtype == 2 )
777  set_monteCarlo();
778 
779  return;
780  }
781 
782  emit process_complete( 9 ); // signal that all processing is complete
783 }
784 
785 // Public slot to get results upon completion of all refinements
787  US_DataIO::RawData* da_res,
788  US_Model* da_mdl,
789  US_Noise* da_tin,
790  US_Noise* da_rin )
791 {
792  bool all_ok = true;
793 
794  if ( abort ) return false;
795 
796  *da_sim = sdata; // copy simulation data
797  *da_res = rdata; // copy residuals data
798  *da_mdl = model; // copy model
799 
800  if ( ( noisflag & 1 ) != 0 && da_tin != 0 )
801  *da_tin = ti_noise; // copy any ti noise
802 
803  if ( ( noisflag & 2 ) != 0 && da_rin != 0 )
804  *da_rin = ri_noise; // copy any ri noise
805 
806 DbgLv(1) << " GET_RES: ti,ri counts" << ti_noise.count << ri_noise.count;
807 DbgLv(1) << " GET_RES: VARI" << rdata.scanData[0].delta_r
808  << da_res->scanData[0].delta_r;
809  return all_ok;
810 }
811 
812 // Submit a job
813 void US_2dsaProcess::submit_job( WorkPacket2D& wtask, int thrx )
814 {
815  wtask.thrn = thrx + 1;
816 
817  WorkerThread2D* wthr = new WorkerThread2D( this );
818  wthreads[ thrx ] = wthr;
819  wkstates[ thrx ] = WORKING;
820  wkdepths[ thrx ] = wtask.depth;
821  wtask.sim_vals.maxrss = maxrss;
822 
823  wthr->define_work( wtask );
824 
825  connect( wthr, SIGNAL( work_complete( WorkerThread2D* ) ),
826  this, SLOT( process_job( WorkerThread2D* ) ) );
827  connect( wthr, SIGNAL( work_progress( int ) ),
828  this, SLOT( step_progress( int ) ) );
829 DbgLv(1) << "SUBMIT_JOB taskx" << wtask.taskx << "depth" << wtask.depth;
830 DbgLv(1) << "SUBMIT_JOB AvailPercent" << US_Memory::memory_profile();
831 
832  wthr->start();
833 }
834 
835 // Slot to handle the results of a just-completed worker thread.
836 // Accumulate computed solutes.
837 // If there is more work to do, start a new thread for a new work unit.
839 {
840  WorkPacket2D wresult;
841 
842  wthrd->get_result( wresult ); // get results of thread task
843  int thrn = wresult.thrn; // thread number of task
844  int thrx = thrn - 1; // index into thread list
845  int taskx = wresult.taskx; // task index of task
846  int depth = wresult.depth; // depth of result
847  maxrss = qMax( maxrss, wresult.sim_vals.maxrss );
848 DbgLv(1) << "PROCESS_JOB thrn" << thrn << "taskx" << taskx
849  << "depth" << wresult.depth;
850  int nrcso = wresult.csolutes.size();
851  ntcsols += nrcso;
852 if ( taskx < 9 || taskx > (nsubgrid-4) )
853 DbgLv(1) << "PJ: taskx csolutes size tot" << taskx << nrcso << ntcsols
854  << QDateTime::currentDateTime().toMSecsSinceEpoch();
855 //DBG-CONC
856 if (dbg_level>0) for (int mm=0; mm<wresult.csolutes.size(); mm++ ) {
857  if ( wresult.csolutes[mm].c > 100.0 ) {
858  DbgLv(1) << "PJ: CONC=" << wresult.csolutes[mm].c
859  << " s,ff0" << wresult.csolutes[mm].s*1.0e+13
860  << wresult.csolutes[mm].k; } }
861 //DBG-CONC
862 //DBG-DATA
863 #if 1
864 if (dbg_level>0)
865 {
866  double dtot=0.0;
867  double ntot=0.0;
868  int nnoi=wresult.ti_noise.count();
869  for (int ii=0; ii<nscans; ii++ )
870  for (int jj=0; jj<npoints; jj++ )
871  dtot += edata->value(ii,jj);
872  for (int jj=0; jj<nnoi; jj++ )
873  ntot += wresult.ti_noise[jj];
874  DbgLv(1) << "PJ:DA DTOT" << dtot << "thr,tsk,ncso" << thrn << taskx << nrcso
875  << "edata" << edata << "nti,NTOT" << nnoi << ntot;
876 }
877 #endif
878 //DBG-DATA
879 
880  max_rss(); // Compute max memory used
881  if ( taskx <= nthreads )
882  memory_check(); // Check for memory use too high
883 
884  free_worker( thrx ); // Free up this worker thread
885 
886  if ( abort ) // Abort if so flagged
887  return;
888 
889  // This loop should only execute, at most, once per result
890  while( c_solutes.size() < ( depth + 1 ) )
891  c_solutes << QVector< US_Solute >();
892 
893  int cs_size = c_solutes[ depth ].size();
894  int wr_size = wresult.csolutes.size();
895  int nextc = cs_size + wr_size;
896  int jnois = fnoionly ? 0 : noisflag;
897  int depthn = depth + 1;
898 
899  if ( depthn > 4 && nextc > maxtsols &&
900  ( ( cs_size / wr_size ) == 1 || ( wr_size / cs_size ) == 1 ) )
901  { // Adjust max solutes per task if it is only large enough for one output
902  maxtsols = ( nextc * 11 + 9 ) / 10;
903  }
904 
905  if ( nextc > maxtsols )
906  { // if new solutes push count over limit, queue a job at next depth
907  WorkPacket2D wtask = wresult;
908  int taskx = tkdepths.size();
909 
910  queue_task( wtask, slolim, klolim, taskx, depthn, jnois,
911  c_solutes[ depth ] );
912 
913  maxdepth = qMax( maxdepth, depthn );
914  c_solutes[ depth ].clear();
915 DbgLv(1) << "THR_FIN: depth" << wtask.depth << " #solutes"
916  << wtask.isolutes.size() << " nextc maxtsols" << nextc << maxtsols
917  << "wres#sols" << wresult.csolutes.size();;
918  }
919 
920  if ( depth == 0 )
921  { // this result is from depth 0, it is from initial subgrids pass
922  kctask++; // bump count of completed subgrid tasks
923 DbgLv(1) << "THR_FIN: thrn" << thrn << " taskx" << taskx
924  << " kct kst" << kctask << kstask << "csols size" << c_solutes.size();
925 
926  emit message_update( pmessage_head() +
927  tr( "Computations for %1 of %2 subgrids are complete" )
928  .arg( kctask ).arg( nsubgrid ), false );
929 
930  if ( kctask == nsubgrid )
931  { // all subgrid tasks are now complete
932  if ( r_iter == 0 )
933  { // in 1st iteration, re-estimate total progress steps
934  int nsolest = ( nksteps * nssteps ) / 8 ; // solutes estimated
935  int nsolact = ntcsols; // actually computed
936 
937  int todoest = estimate_steps( nsolest );
938  int todoact = estimate_steps( nsolact );
939 
940 DbgLv(1) << "THR_FIN: (est)kcst ncto" << kcsteps << nctotal
941  << " nsol ntodo" << nsolest << todoest;
942  // adjust the estimate of total progress steps
943  nctotal = kcsteps + todoact;
944 DbgLv(1) << "THR_FIN: (new)kcst ncto" << kcsteps << nctotal
945  << " nsol ntodo" << nsolact << todoact;
946  }
947 
948  emit stage_complete( kcsteps, nctotal );
949 
950  emit message_update( pmessage_head() +
951  tr( "Computing depth 1 solutions and beyond ..." ), false );
952 
953  int maxdepsv = maxdepth;
954  maxdepth = 1;
955 
956  //if ( nextc <= maxtsols && jobs_at_depth( 1 ) == 0 )
957  if ( nextc <= maxtsols && maxdepsv < 1 )
958  maxdepth = 0; // handle no depth 1 jobs yet submitted
959  }
960  }
961 
962  // Add the current results
963  c_solutes[ depth ] += wresult.csolutes;
964 
965  // At this point we need to clean up. For each depth below the current one,
966  // if there is nothing in the queue or working and there are calculated
967  // solutes left, those need to be submitted
968 
969  for ( int dd = 0; dd < depth; dd++ )
970  {
971  if ( jobs_at_depth( dd ) == 0 && c_solutes[ dd ].size() > 0 )
972  { // queue a task to handle last solutes at this depth
973  WorkPacket2D wtask = wresult;
974  int taskx = tkdepths.size();
975  int depthn = dd + 1;
976 DbgLv(1) << "THR_FIN: QT: taskx depth solsz" << taskx << depth << c_solutes[dd].size();
977  queue_task( wtask, slolim, klolim, taskx, depthn, jnois,
978  c_solutes[ dd ] );
979 
980  c_solutes[ dd ].clear();
981  }
982  }
983 
984  // Is anyone working?
985  bool no_working = wkstates.indexOf( WORKING ) < 0;
986 DbgLv(1) << "THR_FIN: nowk dep mxdp cssz wrsz" << no_working << depth
987  << maxdepth << c_solutes[depth].size() << wresult.csolutes.size();
988 
989  // Submit one last time with all solutes if necessary
990  if ( depth == maxdepth &&
991  job_queue.isEmpty() &&
992  no_working &&
993  c_solutes[ depth ].size() >= wresult.csolutes.size() )
994  {
995  final_computes();
996  return;
997  }
998 DbgLv(1) << "THR_FIN: jqempty" << job_queue.isEmpty() << "ReadyWorkerNdx"
999  << wkstates.indexOf( READY );
1000  int kstsksv = kstask;
1001 
1002  // Submit jobs while queue is not empty and a worker thread is ready
1003  while ( ! job_queue.isEmpty() && ( thrx = wkstates.indexOf( READY ) ) >= 0 )
1004  {
1005  WorkPacket2D wtask = next_job();
1006 
1007  submit_job( wtask, thrx );
1008  kstask++; // bump count of started worker threads
1009 
1010  if ( wtask.depth > 1 &&
1011  wtask.taskx == tkdepths.indexOf( wtask.depth ) )
1012  { // submitting the first job of a depth pass
1013  QString pmsg = tr( "Computing depth %1 solutions..." )
1014  .arg( wtask.depth );
1015  emit message_update( pmsg, true );
1016 DbgLv(1) << pmsg;
1017  }
1018  }
1019 
1020  if ( kstsksv == kstask )
1021  { // No new tasks got started: what's going on?
1022 DbgLv(1) << "THR_FIN: *NONEW* jqempty" << job_queue.isEmpty()
1023  << " ReadyWorkerNdx" << wkstates.indexOf( READY );
1024  if ( depth < maxdepth )
1025  { // If done at depth less than max, see need to queue new task
1026  int dd = depth + 1;
1027  if ( jobs_at_depth( dd ) == 0 && c_solutes[ dd ].size() > 0 )
1028  { // queue a task to handle remaining solutes at next depth
1029  depth = dd;
1030  WorkPacket2D wtask = wresult;
1031  int taskx = tkdepths.size();
1032 DbgLv(1) << "THR_FIN: QT: /NONEW/taskx depth solsz" << taskx << depth
1033  << c_solutes[dd].size();
1034  queue_task( wtask, slolim, klolim, taskx, depth, jnois,
1035  c_solutes[ depth ] );
1036 
1037  c_solutes[ depth ].clear();
1038 
1039  wtask = next_job();
1040  thrx = wkstates.indexOf( READY );
1041 
1042  submit_job( wtask, thrx );
1043 DbgLv(1) << "THR_FIN: QT: /NONEW/ thrx" << thrx;
1044  kstask++; // bump count of started worker threads
1045  }
1046  }
1047  }
1048 
1049 }
1050 
1051 // Build a task and add it to the queue
1052 void US_2dsaProcess::queue_task( WorkPacket2D& wtask, double llss, double llsk,
1053  int taskx, int depth, int noisf, QVector< US_Solute > isolutes )
1054 {
1055  wtask.thrn = 0; // thread number (none while queued)
1056  wtask.taskx = taskx; // task index
1057  wtask.noisf = noisf; // noise flag
1058  wtask.typeref = UGRID; // refinement type: uniform grid
1059  wtask.state = READY; // initialized state, ready for submit
1060  wtask.depth = depth; // depth index
1061  wtask.iter = r_iter; // refine-iteration index
1062  wtask.ll_s = llss; // lower limit s (x 1e13)
1063  wtask.ll_k = llsk; // lower limit k
1064  wtask.dsets = dsets; // pointer to experiment data
1065  wtask.isolutes = isolutes; // solutes for calc_residuals task
1066 
1067  if ( jgrefine == (-2) )
1068  wtask.typeref = jgrefine; // mark if model-ratio grid refinement
1069 
1070  wtask.csolutes.clear(); // clear output vectors
1071  wtask.ti_noise.clear();
1072  wtask.ri_noise.clear();
1073  int nrisols = isolutes.size();
1074  ntisols += nrisols;
1075 if ( taskx < 9 || taskx > (nsubgrid-4) )
1076 DbgLv(1) << "QT: taskx" << taskx << " isolutes size tot" << nrisols << ntisols;
1077 
1078  tkdepths << depth; // record work task depth
1079 
1080  job_queue << wtask; // put the task on the queue
1081 
1082  if ( tkdepths.count( depth ) == 1 )
1083  { // if first task at this depth, report it
1084  emit message_update( tr( "Submitting first depth %1 calculations..." )
1085  .arg( depth ), true );
1086 DbgLv(1) << "Submit 1st calcs, depth" << depth;
1087  }
1088 }
1089 
1090 // queue up jobs for a new iteration
1092 {
1093  r_iter++; // bump iteration index
1094 
1095  tkdepths .clear();
1096  job_queue.clear();
1097  QVector< US_Solute > csolutes = c_solutes[ maxdepth ];
1098  QVector< US_Solute > isolutes;
1099 
1100  int ncsol = csolutes.size(); // number of solutes calculated last iter
1101 DbgLv(1) << "ITER: start of iteration" << r_iter+1 << " mxdp" << maxdepth;
1102 
1103  // Bump total steps estimate based on additional solutes in subgrids
1104  nctotal = ( r_iter == 1 ) ? nctotal : ( ( nctotal + kcsteps ) / 2 );
1105  nctotal = qMax( kcsteps, nctotal ) + 10;
1106 DbgLv(1) << "ITER: r-iter0 ncto ncsol" << nctotal << ncsol;
1107  int ktisol = maxtsols - 5;
1108  int ktask = nsubgrid + 1;
1109  int kstep = ( r_iter == 1 ) ? ( ncsol + 8 ) : 4;
1110  int knois = ktask * ( ( kstep * ktisol + sq( kstep ) ) / 10 );
1111 DbgLv(1) << "ITER: nsubg ktask kstep knois" << nsubgrid << ktask << kstep << knois;
1112  int kadd = ( ktask * kstep ) + ( ( noisflag == 0 ) ? 0 : knois );
1113  nctotal += kadd;
1114 DbgLv(1) << "ITER: r-iter1 ncto (diff)" << nctotal << kadd;
1115 
1116  kcsteps = 0;
1117  emit stage_complete( kcsteps, nctotal );
1118  kctask = 0;
1119  kstask = 0;
1120  maxdepth = 0;
1121  ntisols = 0;
1122  ntcsols = 0;
1123  maxtsols = mintsols;
1124  max_rss();
1125 
1126  int jdpth = 0;
1127  int jnois = fnoionly ? 0 : noisflag;
1128 //*DEBUG
1129 for(int jj=0; jj<ncsol; jj++ )
1130  DbgLv(1) << "ITER: csol" << jj << " s k c"
1131  << csolutes[jj].s*1.e13 << csolutes[jj].k << csolutes[jj].c;
1132 int ktadd=0;
1133 //*DEBUG
1134 
1135  // Build and queue the subgrid tasks
1136  for ( ktask = 0; ktask < nsubgrid; ktask++ )
1137  {
1138  // Get the solutes originally created for this subgrid
1139  isolutes = orig_sols[ ktask ];
1140 
1141  // Add in any calculated solutes not already in this subgrid
1142  for ( int cc = 0; cc < ncsol; cc++ )
1143  {
1144  if ( ! isolutes.contains( csolutes[ cc ] ) )
1145  isolutes << csolutes[ cc ];
1146  }
1147 //*DEBUG
1148 int kosz=orig_sols[ktask].size();
1149 int kasz=isolutes.size();
1150 int kadd=kasz-kosz;
1151 ktadd += (ncsol-kadd);
1152 if ( kadd < ncsol )
1153 DbgLv(1) << "ITER: kt" << ktask << "iterate nisol o a c +"
1154  << kosz << kasz << ncsol << kadd << "ktadd" << ktadd << "nsubg" << nsubgrid;
1155 //*DEBUG
1156  // Queue a subgrid task and update the maximum task solute count
1157  double llss = isolutes[ 0 ].s;
1158  double llsk = isolutes[ 0 ].k;
1159  qSort( isolutes );
1160  WorkPacket2D wtask;
1161  queue_task( wtask, llss, llsk, ktask, jdpth, jnois, isolutes );
1162  maxtsols = qMax( maxtsols, isolutes.size() );
1163  }
1164 
1165 //*DEBUG
1166 if(ktadd<ncsol) {
1167  for(int kt=0;kt<nsubgrid;kt++)
1168  for(int cc=0;cc<orig_sols[kt].size();cc++)
1169  DbgLv(1) << "ITER kt cc" << kt << cc << " s k c"
1170  << orig_sols[kt][cc].s*1.e13 << orig_sols[kt][cc].k << orig_sols[kt][cc].c;
1171 }
1172 //*DEBUG
1173 
1174  // Make sure calculated solutes are cleared out for new iteration
1175  for ( int ii = 0; ii < c_solutes.size(); ii++ )
1176  c_solutes[ ii ].clear();
1177 
1178  // Start the first threads. This will begin the first work units (subgrids).
1179  // Thereafter, work units are started in new threads when threads signal
1180  // that they have completed their work.
1181  for ( int ii = 0; ii < nthreads; ii++ )
1182  {
1183  WorkPacket2D wtask = job_queue.takeFirst();
1184  submit_job( wtask, ii );
1185  }
1186 
1187  max_rss();
1188  kstask = nthreads; // count of started tasks is initially thread count
1189 
1190  emit message_update(
1191  tr( "Starting iteration %1 computations of %2 subgrids\n"
1192  " using %3 threads ..." )
1193  .arg( r_iter + 1 ).arg( nsubgrid ).arg( nthreads ), true );
1194 
1195 }
1196 
1197 // Free up a worker thread
1199 {
1200  if ( tx >= 0 && tx < nthreads )
1201  {
1202  if ( wthreads[ tx ] != 0 )
1203  delete wthreads[ tx ]; // destroy thread
1204 
1205  wthreads[ tx ] = 0; // set thread pointer to null
1206  wkstates[ tx ] = READY; // mark its slot as available
1207  wkdepths[ tx ] = -1; // mark no valid depth yet for worker
1208  }
1209 }
1210 
1211 // Estimate progress steps after depth 0 from given total of calculated solutes.
1212 // For maxtsols=100, estimate 95 solutes per task
1213 // Calculate tasks needed for given depth 0 calculated steps
1214 // Bump a bit for NNLS and any noise
1215 // Multiply steps per task times number of tasks
1216 // Repeat for subsequent depths, assuming calculated solutes 1/8 of input
1218 {
1219  // Estimate number of solutes and steps per task
1220  int ktisol = maxtsols - 5;
1221  int ktcsol = ktisol / 8 + 1;
1222  int ktstep = ktisol + ( ( noisflag > 0 ) ? ( sq( ktisol ) / 10 + 2 ) : 2 );
1223 DbgLv(1) << "ES: ncsol ktisol ktcsol ktstep" << ncsol << ktisol
1224  << ktcsol << ktstep;
1225 
1226  // Estimate number of depth 1 tasks, solutes,and steps
1227  int n1task = ( ncsol + ktisol / 2 ) / ktisol + 1;
1228  int ntasks = n1task + 1;
1229  int n1csol = n1task * ktcsol;
1230 DbgLv(1) << "ES: D1 n1task n1csol" << n1task << n1csol;
1231 
1232  // Estimate number of solutes for depths beyond 1
1233  n1task = ( n1csol + ktisol / 2 ) / ktisol + 1;
1234  ntasks += n1task;
1235  n1csol = n1task * ktcsol;
1236 DbgLv(1) << "ES: D2 n1task n1csol" << n1task << n1csol;
1237 
1238  while ( n1task > 1 )
1239  { // Sum in steps for depth 3 and following until just 1 task left
1240  n1task = ( n1csol + ktisol / 2 ) / ktisol + 1;
1241  ntasks += n1task;
1242  n1csol = n1task * ktcsol;
1243 DbgLv(1) << "ES: D3ff n1task n1csol" << n1task << n1csol;
1244  }
1245 
1246  // Return estimate of remaining steps
1247 DbgLv(1) << "ES: returned nsteps ntasks" << (ntasks*ktstep) << ntasks;
1248 int szscnd = sizeof(US_DataIO::Scan);
1249 int szrdng = sizeof(QVector<double>);
1250 int szsols = sizeof(US_Solute);
1251 int nscns = dsets[0]->run_data.scanData.size();
1252 int nrpts = dsets[0]->run_data.xvalues.size();
1253 int szdata = sizeof(US_DataIO::RawData)+(nscns*szscnd)+(nscns*nrpts*szrdng);
1254 int szsimu = sizeof(US_SolveSim::Simulation)+(2*szdata)+(szsols*ktisol);
1255 int szdset = sizeof(SS_DATASET);
1256 int szwrkp = sizeof(WorkPacket2D);
1257  szwrkp = szwrkp + szsols*100 + szsimu + szdset;
1258 DbgLv(1) << "ES: nscns nrpts ktisol" << nscns << nrpts << ktisol;
1259 DbgLv(1) << "ES: szscnd szrdng szsols" << szscnd << szrdng << szsols;
1260 DbgLv(1) << "ES: szdata szdset szsimu" << szdata << szdset << szsimu;
1261 DbgLv(1) << "ES: szwrkp" << szwrkp;
1262 
1263  return ( ntasks * ktstep );
1264 }
1265 
1266 // count queued jobs at a given depth
1268 {
1269  int count = 0;
1270 
1271  for ( int ii = 0; ii < job_queue.size(); ii++ )
1272  {
1273  if ( job_queue[ ii ].depth == depth )
1274  count++;
1275  }
1276 
1277  return count;
1278 }
1279 
1280 // count running jobs at a given depth
1282 {
1283  int count = 0;
1284 
1285  for ( int ii = 0; ii < nthreads; ii++ )
1286  {
1287  if ( wkstates[ ii ] == WORKING &&
1288  wkdepths[ ii ] == depth &&
1289  wthreads[ ii ] != 0 )
1290  count++;
1291  }
1292 
1293  return count;
1294 }
1295 
1296 // count all queued and running jobs at a given depth
1298 {
1299  return queued_at_depth( depth ) + running_at_depth( depth );
1300 }
1301 
1302 // Set up for another meniscus pass
1304 {
1305  // Give the working data set an appropriate meniscus value
1306  double bmeniscus = bdata->meniscus;
1307  double mendelta = menrange / (double)( mmiters - 1 );
1308  double smeniscus = bmeniscus - menrange * 0.5;
1309  edata->meniscus = smeniscus + (double)mm_iter * mendelta;
1311 DbgLv(1) << "MENISC: mm_iter meniscus" << mm_iter << edata->meniscus;
1312 
1313  // Re-queue all the original subgrid tasks
1314 
1315  requeue_tasks();
1316 }
1317 
1318 // Set up for another monte carlo pass
1320 {
1321 DbgLv(1) << "MCARLO: mm_iter" << mm_iter;
1322  // Set up new data modified by a gaussian distribution (MC iteration 2 start)
1323  if ( mm_iter == 1 )
1324  {
1325  set_gaussians(); // calculate sigmas at 1st mc iteration
1326 
1327  sdata1 = sdata; // save mc iteration 1 simulation
1328  }
1329 
1330  // Get a randomized variation of the concentrations
1331  // Use a gaussian distribution with the residual as the standard deviation
1332  int kk = 0;
1333 
1334  for ( int ss = 0; ss < nscans; ss++ )
1335  {
1336  for ( int rr = 0; rr < npoints; rr++ )
1337  {
1338  double variation = US_Math2::box_muller( 0.0, sigmas[ kk++ ] );
1339  wdata.setValue( ss, rr, ( sdata1.value( ss, rr ) + variation ) );
1340  }
1341  }
1342 
1343  edata = &wdata;
1344 DbgLv(1) << "MCARLO: mm_iter" << mm_iter << " sigma0 c0 v0 cn vn"
1345  << sigmas[0] << bdata->value(0,0) << edata->value(0,0)
1346  << bdata->value(nscans-1,npoints-1) << edata->value(nscans-1,npoints-1);
1347  dsets[ 0 ]->run_data = wdata;
1348 
1349  // Re-queue all the original subgrid tasks
1350 
1351  requeue_tasks();
1352 }
1353 
1354 // Re-queue all the original subgrid tasks
1356 {
1357  kcsteps = 0;
1358  emit stage_complete( kcsteps, nctotal );
1359  int jdpth = 0;
1360  int jnois = 0;
1361 
1362  for ( int ktask = 0; ktask < nsubgrid; ktask++ )
1363  {
1364  double llss = orig_sols[ ktask ][ 0 ].s;
1365  double llsk = orig_sols[ ktask ][ 0 ].k;
1366  // Get the solutes originally created for this subgrid
1367  QVector< US_Solute > isolutes = orig_sols[ ktask ];
1368  WorkPacket2D wtask;
1369  queue_task( wtask, llss, llsk, ktask, jdpth, jnois, isolutes );
1370  }
1371 
1372  // Make sure calculated solutes are cleared out for new iteration
1373  for ( int ii = 0; ii < c_solutes.size(); ii++ )
1374  c_solutes[ ii ].clear();
1375 
1376  // Start the first threads
1377  for ( int ii = 0; ii < nthreads; ii++ )
1378  {
1379  WorkPacket2D wtask = job_queue.takeFirst();
1380  submit_job( wtask, ii );
1381  }
1382 
1383  kstask = nthreads;
1384  kctask = 0;
1385  maxdepth = 0;
1386  ntisols = 0;
1387  ntcsols = 0;
1388  r_iter = 0;
1389 
1390  emit message_update(
1391  tr( "Starting iteration %1 computations of %2 subgrids\n"
1392  " using %3 threads ..." )
1393  .arg( r_iter + 1 ).arg( nsubgrid ).arg( nthreads ), true );
1394 }
1395 
1397 {
1398  bool gausmoo = US_Settings::debug_match( "MC-GaussianSmooth" );
1399  sigmas.clear();
1400 DbgLv(1) << "MCARLO:setgau ns np" << nscans << npoints << "gausmoo" << gausmoo;
1401 
1402  if ( ! gausmoo )
1403  { // Construct sigmas from iteration 1 residuals
1404  for ( int ss = 0; ss < nscans; ss++ )
1405  for ( int rr = 0; rr < npoints; rr++ )
1406  sigmas << qAbs( rdata.value( ss, rr ) );
1407  }
1408 
1409  else
1410  { // Construct sigmas from residuals smoothed for each scan
1411  int ntpoints = nscans * npoints;
1412  double rmsdr = 0.0;
1413  double rmsds = 0.0;
1414 
1415  for ( int ss = 0; ss < nscans; ss++ )
1416  {
1417  QVector< double > vv( npoints );
1418 
1419  for ( int rr = 0; rr < npoints; rr++ )
1420  {
1421  double rval = rdata.value( ss, rr );
1422  rmsdr += sq( rval );
1423  vv[ rr ] = qAbs( rval );
1424  }
1425 
1426 if ( ss < 2 ) DbgLv(1) << "MCARLO:setgau:gausmoo vv9" << vv[9] << "ss" << ss;
1427  // Smooth using 5 points to the left and right of each point
1429 if ( ss < 2 ) DbgLv(1) << "MCARLO:setgau: smoothd vv9" << vv[9];
1430 
1431  sigmas << vv;
1432  }
1433 
1434  // Determine sigmas rmsd, then scale to match residuals rmsd
1435  for ( int rr = 0; rr < ntpoints; rr++ )
1436  rmsds += sq( sigmas[ rr ] );
1437 
1438  rmsdr = sqrt( rmsdr / (double)ntpoints ); // Residuals RMSD
1439  rmsds = sqrt( rmsds / (double)ntpoints ); // Sigmas RMSD
1440  double sigscl = rmsdr / rmsds; // Sigma scale factor
1441 
1442  for ( int rr = 0; rr < ntpoints; rr++ )
1443  sigmas[ rr ] *= sigscl; // Scaled sigmas
1444  }
1445 }
1446 
1448 {
1449  return tr( "Model %1, Iteration %2:\n" )
1450  .arg( mm_iter + 1 ).arg( r_iter + 1 );
1451 }
1452 
1453 // Get next job from queue, insuring we get the lowest depth
1455 {
1456  WorkPacket2D wtask;
1457  if ( job_queue.size() == 0 ) return wtask;
1458 
1459  int jobx = 0;
1460  wtask = job_queue[ jobx ];
1461  int depth = wtask.depth;
1462 
1463  if ( depth > 0 )
1464  { // If first is beyond depth 0, insure what we get is lowest depth
1465 
1466  for ( int ii = 0; ii < job_queue.size(); ii++ )
1467  {
1468  if ( job_queue[ ii ].depth < depth )
1469  {
1470  wtask = job_queue[ ii ];
1471  depth = wtask.depth;
1472  jobx = ii;
1473  }
1474  }
1475  }
1476 if(jobx>0) {
1477 DbgLv(1) << "NEXTJ: jobx depth depth0 taskx taskx0"
1478  << jobx << depth << job_queue[0].depth << wtask.taskx << job_queue[0].taskx; }
1479 else {
1480 DbgLv(1) << "NEXTJ: jobx depth taskx" << jobx << depth << wtask.taskx; }
1481 DbgLv(1) << "NEXTJ: wtask" << &wtask << &job_queue[jobx];
1482 
1483  job_queue.removeAt( jobx ); // Remove job from queue
1484  return wtask;
1485 }
1486 
1487 // Return flag of whether a memory check implies fits should be aborted
1489 {
1490  bool stopfit = false;
1491  int memava, memtot, memuse;
1492  int mempav = US_Memory::memory_profile( &memava, &memtot, &memuse );
1493 DbgLv(1) << "MCk:MEM: AvailPercent" << mempav;
1494 
1495 #if 0
1496  if ( mempav < 10 )
1497  {
1498 DbgLv(0) << "MCk:MEM: *** AvailPercent < 10 ***";
1499  stop_fit();
1500  QMessageBox::warning( (QWidget*)parentw, tr( "High Memory Usage" ),
1501  tr( "The available memory percent of\n"
1502  "the total memory has fallen below 10%.\n"
1503  "Total memory is %1 MB;\n"
1504  "Used memory is %2 MB;\n"
1505  "Available memory is %3 MB.\n\n"
1506  "Re-parameterize the fit with adjusted\n"
1507  "Grid Refinements and/or Thread Count." )
1508  .arg( memtot ).arg( memuse ).arg( memava ) );
1509 
1510  emit process_complete( 6 ); // signal memory-related stop
1511  abort = true;
1512  stopfit = true;
1513  }
1514 #endif
1515 
1516  return stopfit;
1517 }
1518