UltraScan III
us_simparms.cpp
Go to the documentation of this file.
1 
3 #include "us_simparms.h"
4 #include "us_astfem_math.h"
5 #include "us_hardware.h"
6 #include "us_settings.h"
7 #include "us_constants.h"
8 #include "us_math2.h"
9 
11 #define DbgLv(a) if(dbg_level>=a)qDebug()
12 
14 {
15  mesh_radius.clear();
16  speed_step.clear();
17 
19 
20  simpoints = 200;
21  meshType = ASTFEM;
22  gridType = MOVING;
23  radial_resolution = 0.001;
24  meniscus = 5.8;
25  bottom = 7.2;
26  rnoise = 0.0;
27  tinoise = 0.0;
28  rinoise = 0.0;
30  rotorCalID = "0";
31  band_forming = false;
32  band_volume = 0.015;
33  bottom_position = 7.2;
34  rotorcoeffs[ 0 ] = 0.0;
35  rotorcoeffs[ 1 ] = 0.0;
36  cp_sector = 0;
37  cp_pathlen = 1.2;
38  cp_angle = 2.5;
39  cp_width = 0.0;
40 
42 }
43 
45 {
46  duration_hours = 0;
47  duration_minutes = 0.0;
48  delay_hours = 0;
49  delay_minutes = 0.0;
50  scans = 0;
51  rotorspeed = 0;
52  acceleration = 400;
53  acceleration_flag = true;
54  w2t_first = 0.0;
55  w2t_last = 0.0;
56  time_first = 0;
57  time_last = 0;
58 
59  avg_speed = 0.0;
60  speed_stddev = 0.0;
61  set_speed = 0;
62 }
63 
64 // Set simulation parameter values from an experimental RawData set.
66  US_DataIO::RawData& rawdata, bool incl_speed, QString runID, QString dataType )
67 {
68  SpeedProfile sp;
69 
70  int dbg_level = US_Settings::us_debug();
71  int cp_id = 0;
72  QString channel = QChar(rawdata.channel);
73  int iechan = QString( "ABCDEFGH" ).indexOf( channel );
74  int ch = qMax( 0, iechan ) / 2;
75  iechan = qMax( 0, iechan ) + 1;
76  QString ecell = QString::number(rawdata.cell);
77  int iecell = ecell.toInt();
78 DbgLv(1) << "SP:iFD: cell chan ch" << ecell << channel << ch
79  << rawdata.channel << (ch+1);
80 
81  rotorCalID = "0";
82  QString fn = US_Settings::resultDir() + "/" + runID + "/"
83  + runID + "." + dataType + ".xml";
84  QFile file( fn );
85 
86  if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
87  { // If experiment/run file exists, get calibration,centerpiece IDs from it
88  QXmlStreamReader xml( &file );
89  int dcp_id = 0;
90  int dcell = 0;
91  QString dchan = "";
92 
93  while ( ! xml.atEnd() )
94  {
95  xml.readNext();
96 
97  if ( xml.isStartElement() && xml.name() == "calibration" )
98  { // Pick up rotor calibration ID from <calibration ... id=...
99  QXmlStreamAttributes a = xml.attributes();
100  rotorCalID = a.value( "id" ).toString();
101  rotorcoeffs[ 0 ] = a.value( "coeff1" ).toString().toDouble();
102  rotorcoeffs[ 1 ] = a.value( "coeff2" ).toString().toDouble();
103  }
104 
105  if ( xml.isStartElement() && xml.name() == "dataset" )
106  { // Pick up cell and channel for comparison
107  QXmlStreamAttributes a = xml.attributes();
108  dcell = a.value( "cell" ).toString().toInt();
109  dchan = a.value( "channel" ).toString();
110  }
111 
112  if ( xml.isStartElement() && xml.name() == "centerpiece" )
113  { // Pick up centerpiece ID from <centerpiece ... id=...
114  QXmlStreamAttributes a = xml.attributes();
115  dcp_id = a.value( "id" ).toString().toInt();
116 DbgLv(1) << "SP:iFD: dcell dchan" << dcell << dchan;
117  if ( dcell == iecell && dchan == channel )
118  { // If cell,channel match edit, pick up CpID
119  cp_id = dcp_id;
120 DbgLv(1) << "SP:iFD: cp_id" << cp_id;
121  }
122  }
123  }
124 
125  file.close();
126 
127  if ( cp_id == 0 ) // If no cell,chan match; use last CP ID
128  cp_id = dcp_id;
129  }
130 //DbgLv(2) << "SP:iFD: cp_id ch" << cp_id << ch;
131 
132  bottom_position = 7.2;
133 
134  if ( incl_speed )
136 
137 #ifndef NO_DB
138  double rpm = rawdata.scanData[ 0 ].rpm;
139  if ( db != NULL )
140  { // If reading from the database, get rotor,centerpiece info from DB
141  int stat_db = 0;
142  bool ok_db;
143  QString expID;
144  QStringList query;
145  QString rcalIDsv = rotorCalID; // Save IDs gotten from local file
146  int cpIDsv = cp_id;
147 //DbgLv(2) << "Sim parms:runID" << runID;
148 //DbgLv(2) << "Sim parms:invID" << US_Settings::us_inv_ID();
149  query << "get_experiment_info_by_runID"
150  << runID
151  << QString::number( US_Settings::us_inv_ID() );
152  db->query( query );
153  stat_db = db->lastErrno();
154 //DbgLv(2) << "Sim parms:query() stat" << stat_db;
155  if ( stat_db != US_DB2::NOROWS )
156  { // Info by runID: experiment and calibration IDs
157  ok_db = db->next();
158 //DbgLv(2) << "Sim parms: next() ok_db" << ok_db;
159  if ( ok_db )
160  {
161  expID = db->value( 1 ).toString();
162  rotorCalID = db->value( 7 ).toString();
163 //DbgLv(2) << "Sim parms: expID" << expID;
164 //DbgLv(2) << "Sim parms: rotorCalID" << rotorCalID << "sv" << rcalIDsv;
165  }
166  else
167  rotorCalID = "";
168 
169  if ( rotorCalID.isEmpty() && ! expID.isEmpty() )
170  { // If still no calibration ID, try it another way
171  query.clear();
172  query << "get_experiment_info" << expID;
173  db->query( query );
174  stat_db = db->lastErrno();
175  if ( stat_db != US_DB2::NOROWS && db->next() )
176  {
177  rotorCalID = db->value( 7 ).toString();
178 //DbgLv(2) << "Sim parms(2): rotorCalID" << rotorCalID;
179  }
180  }
181 
182  // If unable to get calibration ID from DB, fall back to local info
183  if ( rotorCalID.isEmpty() || rotorCalID == "0" )
184  rotorCalID = rcalIDsv;
185 //DbgLv(2) << "Sim parms(3): rotorCalID" << rotorCalID;
186 
187  if ( ! expID.isEmpty() )
188  { // Get centerpiece ID from cell records for this experiment
189  query.clear();
190  query << "all_cell_experiments" << expID;
191  db->query( query );
192  while ( db->next() )
193  {
194  int cell = db->value( 2 ).toInt();
195  int ichan = db->value( 3 ).toInt();
196  int cellCpId = db->value( 4 ).toInt();
197 
198 DbgLv(1) << "Sim parms: cell iecell ichan iechan" << cell << iecell
199  << ichan << iechan << "ccId" << cellCpId;
200  if ( cellCpId > 0 && cell == iecell && ichan == iechan )
201  { // Valid CpID with cell,channel matching edit
202  cp_id = cellCpId;
203  break;
204  }
205  }
206  }
207 
208 DbgLv(1) << "Sim parms: cp_id" << cp_id << "sv" << cpIDsv;
209  // If no centerpiece ID from DB, fall back to local info
210  if ( cp_id < 1 )
211  cp_id = cpIDsv;
212 //DbgLv(2) << "Sim parms(2): cp_id" << cp_id;
213  }
214  }
215 
216  // Set rotor coefficients, channel bottom position from hardware files
217  setHardware( db, rotorCalID, -cp_id, ch );
218 
219  // Calculate bottom using RPM, start bottom, and rotor coefficients
221 #else
222  // For NO_DB (back end) the bottom needs to be set after this function
224  db = NULL; // Stop compiler warning
225 #endif
226 DbgLv(2) << "SP:iFD: bottom" << bottom;
227 }
228 
229 // Set simulation parameter values from an experimental EditedData set.
231  US_DataIO::EditedData& editdata, bool incl_speed )
232 {
233  SpeedProfile sp;
234 
235  int dbg_level = US_Settings::us_debug();
236  int cp_id = 0;
237  QString channel = editdata.channel;
238  int iechan = QString( "ABCDEFGH" ).indexOf( channel );
239  int ch = qMax( 0, iechan ) / 2;
240  iechan = qMax( 0, iechan ) + 1;
241  QString ecell = editdata.cell;
242  int iecell = ecell.toInt();
243 DbgLv(1) << "SP:iFD: cell chan ch" << ecell << channel << ch
244  << editdata.channel << (ch+1);
245 
246  rotorCalID = "0";
247  QString fn = US_Settings::resultDir() + "/" + editdata.runID + "/"
248  + editdata.runID + "." + editdata.dataType + ".xml";
249  QFile file( fn );
250 
251  if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
252  { // If experiment/run file exists, get calibration,centerpiece IDs from it
253  QXmlStreamReader xml( &file );
254  int dcp_id = 0;
255  int dcell = 0;
256  QString dchan = "";
257 
258  while ( ! xml.atEnd() )
259  {
260  xml.readNext();
261 
262  if ( xml.isStartElement() && xml.name() == "calibration" )
263  { // Pick up rotor calibration ID from <calibration ... id=...
264  QXmlStreamAttributes a = xml.attributes();
265  rotorCalID = a.value( "id" ).toString();
266  rotorcoeffs[ 0 ] = a.value( "coeff1" ).toString().toDouble();
267  rotorcoeffs[ 1 ] = a.value( "coeff2" ).toString().toDouble();
268  }
269 
270  if ( xml.isStartElement() && xml.name() == "dataset" )
271  { // Pick up cell and channel for comparison
272  QXmlStreamAttributes a = xml.attributes();
273  dcell = a.value( "cell" ).toString().toInt();
274  dchan = a.value( "channel" ).toString();
275  }
276 
277  if ( xml.isStartElement() && xml.name() == "centerpiece" )
278  { // Pick up centerpiece ID from <centerpiece ... id=...
279  QXmlStreamAttributes a = xml.attributes();
280  dcp_id = a.value( "id" ).toString().toInt();
281 DbgLv(1) << "SP:iFD: dcell dchan" << dcell << dchan;
282  if ( dcell == iecell && dchan == channel )
283  { // If cell,channel match edit, pick up CpID
284  cp_id = dcp_id;
285 DbgLv(1) << "SP:iFD: cp_id" << cp_id;
286  }
287  }
288  }
289 
290  file.close();
291 
292  if ( cp_id == 0 ) // If no cell,chan match; use last CP ID
293  cp_id = dcp_id;
294  }
295 //DbgLv(2) << "SP:iFD: cp_id ch" << cp_id << ch;
296 
297  bottom_position = 7.2;
298  meniscus = editdata.meniscus;
299 
300  if ( incl_speed )
301  computeSpeedSteps( &editdata.scanData, speed_step );
302 
303 #ifndef NO_DB
304  double rpm = editdata.scanData[ 0 ].rpm;
305  if ( db != NULL )
306  { // If reading from the database, get rotor,centerpiece info from DB
307  int stat_db = 0;
308  bool ok_db;
309  QString expID;
310  QStringList query;
311  QString rcalIDsv = rotorCalID; // Save IDs gotten from local file
312  int cpIDsv = cp_id;
313 //DbgLv(2) << "Sim parms:runID" << editdata.runID;
314 //DbgLv(2) << "Sim parms:invID" << US_Settings::us_inv_ID();
315  query << "get_experiment_info_by_runID"
316  << editdata.runID
317  << QString::number( US_Settings::us_inv_ID() );
318  db->query( query );
319  stat_db = db->lastErrno();
320 //DbgLv(2) << "Sim parms:query() stat" << stat_db;
321  if ( stat_db != US_DB2::NOROWS )
322  { // Info by runID: experiment and calibration IDs
323  ok_db = db->next();
324 //DbgLv(2) << "Sim parms: next() ok_db" << ok_db;
325  if ( ok_db )
326  {
327  expID = db->value( 1 ).toString();
328  rotorCalID = db->value( 7 ).toString();
329 //DbgLv(2) << "Sim parms: expID" << expID;
330 //DbgLv(2) << "Sim parms: rotorCalID" << rotorCalID << "sv" << rcalIDsv;
331  }
332  else
333  rotorCalID = "";
334 
335  if ( rotorCalID.isEmpty() && ! expID.isEmpty() )
336  { // If still no calibration ID, try it another way
337  query.clear();
338  query << "get_experiment_info" << expID;
339  db->query( query );
340  stat_db = db->lastErrno();
341  if ( stat_db != US_DB2::NOROWS && db->next() )
342  {
343  rotorCalID = db->value( 7 ).toString();
344 //DbgLv(2) << "Sim parms(2): rotorCalID" << rotorCalID;
345  }
346  }
347 
348  // If unable to get calibration ID from DB, fall back to local info
349  if ( rotorCalID.isEmpty() || rotorCalID == "0" )
350  rotorCalID = rcalIDsv;
351 //DbgLv(2) << "Sim parms(3): rotorCalID" << rotorCalID;
352 
353  if ( ! expID.isEmpty() )
354  { // Get centerpiece ID from cell records for this experiment
355  query.clear();
356  query << "all_cell_experiments" << expID;
357  db->query( query );
358  while ( db->next() )
359  {
360  int cell = db->value( 2 ).toInt();
361  int ichan = db->value( 3 ).toInt();
362  int cellCpId = db->value( 4 ).toInt();
363 
364 DbgLv(1) << "Sim parms: cell iecell ichan iechan" << cell << iecell
365  << ichan << iechan << "ccId" << cellCpId;
366  if ( cellCpId > 0 && cell == iecell && ichan == iechan )
367  { // Valid CpID with cell,channel matching edit
368  cp_id = cellCpId;
369  break;
370  }
371  }
372  }
373 
374 DbgLv(1) << "Sim parms: cp_id" << cp_id << "sv" << cpIDsv;
375  // If no centerpiece ID from DB, fall back to local info
376  if ( cp_id < 1 )
377  cp_id = cpIDsv;
378 //DbgLv(2) << "Sim parms(2): cp_id" << cp_id;
379  }
380  }
381 
382  // Set rotor coefficients, channel bottom position from hardware files
383  setHardware( db, rotorCalID, -cp_id, ch );
384 
385  // Calculate bottom using RPM, start bottom, and rotor coefficients
387 #else
388  // For NO_DB (back end) the bottom needs to be set after this function
390  db = NULL; // Stop compiler warning
391 #endif
392 DbgLv(2) << "SP:iFD: bottom" << bottom;
393 }
394 
395 // Read the speed steps vector from runID file
396 int US_SimulationParameters::readSpeedSteps( QString runID, QString dataType,
397  QVector< US_SimulationParameters::SpeedProfile >& speedsteps )
398 {
399  speedsteps.clear();
400  SpeedProfile sp;
401  int nsteps = 0;
402  int dbg_level = US_Settings::us_debug();
403  QString fn = US_Settings::resultDir() + "/" + runID + "/"
404  + runID + "." + dataType + ".xml";
405  QFile filei( fn );
406 
407  if ( filei.open( QIODevice::ReadOnly | QIODevice::Text ) )
408  { // If experiment/run file exists, get speed steps from it
409 DbgLv(1) << "SP:rSS: fn" << fn;
410  QXmlStreamReader xml( &filei );
411 
412  while ( ! xml.atEnd() )
413  {
414  xml.readNext();
415 
416  if ( xml.isStartElement() && xml.name() == "speedstep" )
417  {
418  speedstepFromXml( xml, sp );
419 
420  speedsteps << sp;
421  nsteps++;
422 DbgLv(1) << "SP:rSS: step" << nsteps << "rotorspeed" << sp.rotorspeed
423  << "avg_speed" << sp.avg_speed;
424  }
425  }
426 
427  filei.close();
428  }
429 
430  return nsteps;
431 }
432 
433 // Compute the speed steps vector from data scans
435  QVector< US_DataIO::Scan >* scans,
436  QVector< US_SimulationParameters::SpeedProfile >& speedsteps )
437 {
438  SpeedProfile sp;
439  speedsteps.clear();
440  int dbg_level = US_Settings::us_debug();
441  int scanCount = (*scans).size();
442  double time1 = (*scans)[ 0 ].seconds;
443  double time2 = 0.0;
444  double w2t1 = (*scans)[ 0 ].omega2t;
445  double w2t2 = 0.0;
446  double delay_secs = time1;
447  double rpm = (*scans)[ 0 ].rpm;
448  double rpmnext = rpm;
449  double step_secs = 0.0;
450  int lscx = 0;
451  double rpm_sum = rpm;
452 DbgLv(1) << "SP:cSS: scan" << 1 << "rpm time omega2t"
453  << rpm << qRound(time1) << (*scans)[ 0 ].omega2t;
454 
455  for ( int ii = 1; ii < scanCount; ii++ )
456  { // Loop to build speed steps where RPM changes
457  rpm = rpmnext;
458  rpmnext = (*scans)[ ii ].rpm;
459  // Get set_speeds, the speeds rounded to nearest 100
460  int ss_next = qRound( rpmnext * 0.01 ) * 100;
461  int ss_curr = qRound( rpm * 0.01 ) * 100;
462 DbgLv(1) << "SP:cSS: scan" << (ii+1) << "rpm time omega2t"
463  << rpmnext << qRound((*scans)[ii].seconds) << (*scans)[ii].omega2t;
464 
465  if ( ss_curr != ss_next )
466  { // RPM has changed, so need to create speed step for previous scans
467  time2 = (*scans)[ ii - 1 ].seconds;
468  w2t2 = (*scans)[ ii - 1 ].omega2t;
469  step_secs = time2 - time1 + delay_secs;
470  sp.duration_hours = (int)( step_secs / 3600.0 );
471  sp.duration_minutes = ( step_secs / 60.0 )
472  - ( (double)sp.duration_hours * 60.0 );
473  sp.delay_hours = (int)( delay_secs / 3600.0 );
474  sp.delay_minutes = ( delay_secs / 60.0 )
475  - ( (double)sp.delay_hours * 60.0 );
476  sp.scans = ii - lscx;
477  sp.w2t_first = w2t1;
478  sp.w2t_last = w2t2;
479  sp.time_first = qRound( time1 );
480  sp.time_last = qRound( time2 );
481  sp.avg_speed = rpm_sum / (double)sp.scans;
482  sp.rotorspeed = qRound( sp.avg_speed );
483  sp.set_speed = ( ( sp.rotorspeed + 50 ) / 100 ) * 100;
484  sp.speed_stddev = 0.0;
485  for ( int jj = lscx; jj < ii; jj++ )
486  sp.speed_stddev += sq( (*scans)[ jj ].rpm - sp.avg_speed );
487  sp.speed_stddev = sqrt( sp.speed_stddev ) / (double)sp.scans;
488 
489  speedsteps << sp;
490 DbgLv(1) << "SP:cSS: speedsteps" << speedsteps.size() << "scans" << sp.scans
491  << "duration h m" << sp.duration_hours << sp.duration_minutes
492  << "delay h m" << sp.delay_hours << sp.delay_minutes << "rpm" << rpm;
493 DbgLv(1) << "SP:cSS: w2t1 w2t2 time1 time2" << sp.w2t_first << sp.w2t_last
494  << sp.time_first << sp.time_last;
495 DbgLv(1) << "SP:cSS: sp set avg sdev" << sp.set_speed << sp.avg_speed
496  << sp.speed_stddev;
497 
498  lscx = ii;
499  rpm = rpmnext;
500  time1 = (*scans)[ ii ].seconds;
501  w2t1 = (*scans)[ ii ].omega2t;
502  delay_secs = time1 - time2;
503  rpm_sum = 0.0;
504  }
505 
506  rpm_sum += rpm;
507  }
508 
509  // Set final (only?) speed step
510  time2 = (*scans)[ scanCount - 1 ].seconds;
511  w2t2 = (*scans)[ scanCount - 1 ].omega2t;
512  step_secs = time2 - time1 + delay_secs;
513  sp.duration_hours = (int)( step_secs / 3600.0 );
514  sp.duration_minutes = ( step_secs / 60.0 )
515  - ( (double)sp.duration_hours * 60.0 );
516  sp.delay_hours = (int)( delay_secs / 3600.0 );
517  sp.delay_minutes = ( delay_secs / 60.0 )
518  - ( (double)sp.delay_hours * 60.0 );
519  sp.scans = scanCount - lscx;
520  sp.w2t_first = w2t1;
521  sp.w2t_last = w2t2;
522  sp.time_first = qRound( time1 );
523  sp.time_last = qRound( time2 );
524  sp.avg_speed = rpm_sum / (double)sp.scans;
525  sp.rotorspeed = qRound( sp.avg_speed );
526  sp.set_speed = ( ( sp.rotorspeed + 50 ) / 100 ) * 100;
527  sp.speed_stddev = 0.0;
528  for ( int jj = lscx; jj < scanCount; jj++ )
529  sp.speed_stddev += sq( (*scans)[ jj ].rpm - sp.avg_speed );
530  sp.speed_stddev = sqrt( sp.speed_stddev ) / (double)sp.scans;
531 
532  speedsteps << sp;
533 DbgLv(1) << "SP:cSS: speedsteps" << speedsteps.size() << "scans" << sp.scans
534  << "duration h m" << sp.duration_hours << sp.duration_minutes
535  << "delay h m" << sp.delay_hours << sp.delay_minutes << "rpm" << rpm;
536 DbgLv(1) << "SP:cSS: w2t1 w2t2 time1 time2" << sp.w2t_first << sp.w2t_last
537  << sp.time_first << sp.time_last;
538 DbgLv(1) << "SP:cSS: sp set avg sdev" << sp.set_speed << sp.avg_speed
539  << sp.speed_stddev;
540 }
541 
542 // Set parameters from hardware files, related to rotor and centerpiece
544  int cp, int ch )
545 {
546  int dbg_level = US_Settings::us_debug();
547  rotorCalID = rCalID;
548  bottom_position = 7.2;
549 //DbgLv(2) << "sH: cp ch rCalID" << cp << ch << rCalID;
550 
551  QList< US_AbstractCenterpiece > cp_list;
552  QMap < QString, QString > rotor_map;
553  rotor_map.clear();
554 
555  if ( US_AbstractCenterpiece::read_centerpieces( db, cp_list ) )
556  {
557  if ( cp < 0 )
558  { // If cp given is negative, this means look for a serial number
559  int cp_id = -cp;
560  cp = 0;
561 
562  for ( int jj = 0; jj < cp_list.size(); jj++ )
563  {
564  if ( cp_id == cp_list[ jj ].serial_number )
565  { // Replace cp value (serial) with an index in the list
566  cp = jj;
567  break;
568  }
569  }
570 DbgLv(1) << "sH: cp ch cp_id" << cp << ch << cp_id;
571  }
572 
573  // Pick up centerpiece info by Centerpiece and Channel indecies
574  QStringList shapes;
575  shapes << "sector" << "standard" << "rectangular" << "band forming"
576  << "meniscus matching" << "circular" << "synthetic";
577  QString shape = cp_list[ cp ].shape;
578  bottom_position = cp_list[ cp ].bottom_position[ ch ];
579  cp_pathlen = cp_list[ cp ].path_length [ ch ];
580  cp_angle = cp_list[ cp ].angle;
581  cp_width = cp_list[ cp ].width;
582  cp_sector = qMax( 0, shapes.indexOf( shape ) );
583  band_forming = ( shape == "band forming" );
584 
585  }
586 
587  if ( US_Hardware::readRotorMap( db, rotor_map ) )
588  { // Get rotor coefficients by matching calibration ID
590  }
591 
592  else
593  qDebug() << "setHardware:readRotorMap *ERROR*";
594 
595  return;
596 }
597 
598 // Set parameters from hardware files, related to rotor and centerpiece (Local)
599 void US_SimulationParameters::setHardware( QString rCalID, int cp, int ch )
600 {
601  return setHardware( NULL, rCalID, cp, ch );
602 }
603 
604 // Load simulation parameters from file
606 {
607  int stat = 0;
608  int kr = 0;
609  QStringList meshlist;
610  QStringList gridlist;
611  meshlist << "ASTFEM" << "Claverie" << "MovingHat" << "User" << "ASTFVM";
612  gridlist << "Fixed" << "Moving";
614 
615  QFile xfile( fname );
616 
617  if ( xfile.open( QIODevice::ReadOnly | QIODevice::Text ) )
618  {
619  QXmlStreamReader xml( &xfile );
620  QXmlStreamAttributes a;
621  QString astr;
622  int kk;
623  speed_step.clear();
624 
625  while ( ! xml.atEnd() )
626  {
627  xml.readNext();
628 
629  if ( xml.isStartElement() && xml.name() == "params" )
630  {
631  a = xml.attributes();
632 
633  astr = a.value( "meshType" ).toString();
634  if ( !astr.isEmpty() )
635  {
636  kk = meshlist.indexOf( astr );
638  }
639  astr = a.value( "gridType" ).toString();
640  if ( !astr.isEmpty() )
641  {
642  kk = gridlist.indexOf( astr );
644  }
645  astr = a.value( "simpoints" ).toString();
646  if ( !astr.isEmpty() )
647  simpoints = astr.toInt();
648  astr = a.value( "radialres" ).toString();
649  if ( !astr.isEmpty() )
650  radial_resolution = astr.toDouble();
651  astr = a.value( "meniscus" ).toString();
652  if ( !astr.isEmpty() )
653  meniscus = astr.toDouble();
654  astr = a.value( "bottom" ).toString();
655  if ( !astr.isEmpty() )
656  bottom = astr.toDouble();
657  astr = a.value( "rnoise" ).toString();
658  if ( !astr.isEmpty() )
659  rnoise = astr.toDouble();
660  astr = a.value( "tinoise" ).toString();
661  if ( !astr.isEmpty() )
662  tinoise = astr.toDouble();
663  astr = a.value( "rinoise" ).toString();
664  if ( !astr.isEmpty() )
665  rinoise = astr.toDouble();
666  astr = a.value( "temperature" ).toString();
667  if ( !astr.isEmpty() )
668  temperature = astr.toDouble();
669  astr = a.value( "bandform" ).toString();
670  if ( !astr.isEmpty() )
671  band_forming = ( astr == "yes" || astr == "1" );
672  else
673  band_forming = false;
674  if ( band_forming )
675  band_volume = a.value( "bandvolume" ).toString().toDouble();
676  else
677  band_volume = 0.0;
678  astr = a.value( "rotorCalID" ).toString();
679  if ( !astr.isEmpty() )
680  rotorCalID = astr;
681  astr = a.value( "rotorcoeffs" ).toString().simplified();
682  if ( !astr.isEmpty() )
683  {
684  rotorcoeffs[ 0 ] = astr.section( " ", 0, 0 ).toDouble();
685  rotorcoeffs[ 1 ] = astr.section( " ", 1, 1 ).toDouble();
686  }
687  astr = a.value( "sector" ).toString();
688  if ( !astr.isEmpty() )
689  cp_sector = astr.toInt();
690  astr = a.value( "pathlength" ).toString();
691  if ( !astr.isEmpty() )
692  cp_pathlen = astr.toDouble();
693  astr = a.value( "angle" ).toString();
694  if ( !astr.isEmpty() )
695  cp_angle = astr.toDouble();
696  astr = a.value( "width" ).toString();
697  if ( !astr.isEmpty() )
698  cp_width = astr.toDouble();
699  }
700 
701  else if ( xml.isStartElement() && xml.name() == "speedstep" )
702  {
703  speedstepFromXml( xml, sp );
704 
705  speed_step.append( sp );
706  }
707 
708  else if ( xml.isStartElement() && xml.name() == "usermesh" )
709  {
710  a = xml.attributes();
711 
712  if ( kr == 0 )
713  mesh_radius.clear();
714 
715  kr++;
716  mesh_radius << a.value( "radius" ).toString().toDouble();
717  }
718  }
719  }
720 
721  else
722  {
723  stat = -1;
724  }
725 
726  return stat;
727 }
728 
729 // Save simulation parameters to file
731 {
732  int stat = 0;
733  const char* mesh[] = { "ASTFEM", "Claverie", "MovingHat", "User", "ASTFVM" };
734  const char* grid[] = { "Fixed", "Moving" };
736 
737  QFile xfile( fname );
738 
739  if ( xfile.open( QIODevice::WriteOnly | QIODevice::Text ) )
740  {
741  QXmlStreamWriter xml( &xfile );
742  xml.setAutoFormatting( true );
743 
744  xml.writeStartDocument();
745  xml.writeDTD ( "<!DOCTYPE US_SimParams>" );
746  xml.writeStartElement( "SimParams" );
747  xml.writeAttribute ( "version", "1.0" );
748 
749  xml.writeStartElement( "params" );
750  xml.writeAttribute ( "meshType", QString( mesh[ (int)meshType ] ) );
751  xml.writeAttribute ( "gridType", QString( grid[ (int)gridType ] ) );
752  xml.writeAttribute ( "simpoints", QString::number( simpoints ) );
753  xml.writeAttribute ( "radialres", QString::number( radial_resolution ));
754  xml.writeAttribute ( "meniscus", QString::number( meniscus ) );
755  xml.writeAttribute ( "bottom", QString::number( bottom ) );
756  xml.writeAttribute ( "rnoise", QString::number( rnoise ) );
757  xml.writeAttribute ( "tinoise", QString::number( tinoise ) );
758  xml.writeAttribute ( "rinoise", QString::number( rinoise ) );
759  xml.writeAttribute ( "temperature", QString::number( temperature ) );
760 
761  if ( ! rotorCalID.isEmpty() )
762  xml.writeAttribute ( "rotorCalID", rotorCalID );
763 
764  if ( rotorcoeffs[ 0 ] != 0.0 )
765  {
766  xml.writeAttribute ( "rotorcoeffs", QString().sprintf( "%.3e %.3e",
767  rotorcoeffs[ 0 ], rotorcoeffs[ 1 ] ) );
768  }
769 
770  xml.writeAttribute ( "bandform", band_forming ? "1" : "0" );
771 
772  if ( band_forming )
773  xml.writeAttribute ( "bandvolume", QString::number( band_volume ) );
774 
775  xml.writeAttribute ( "sector", QString::number( cp_sector ) );
776  xml.writeAttribute ( "pathlength", QString::number( cp_pathlen ) );
777  xml.writeAttribute ( "angle", QString::number( cp_angle ) );
778  xml.writeAttribute ( "width", QString::number( cp_width ) );
779 
780  if ( meshType == US_SimulationParameters::USER )
781  {
782  for ( int ii = 0; ii < mesh_radius.size(); ii++ )
783  {
784  xml.writeStartElement( "usermesh" );
785  xml.writeAttribute( "radius",
786  QString().sprintf( "%11.5e", mesh_radius[ ii ] ).simplified() );
787  xml.writeEndElement();
788  }
789  }
790 
791  for ( int ii = 0; ii < speed_step.size(); ii++ )
792  {
793  spi = &speed_step[ ii ];
794 
795  speedstepToXml( xml, spi );
796  }
797 
798  xml.writeEndElement (); // params
799  xml.writeEndElement (); // SimParams
800 
801  xml.writeEndDocument ();
802  xfile.close();
803  }
804 
805  else
806  {
807  stat = -1;
808  }
809 
810  return stat;
811 }
812 
813 // Load simulation parameters from file
815  QString fname )
816 {
817  return sparms.load_simparms( fname );
818 }
819 
820 // Save simulation parameters to file
822  QString fname )
823 {
824  return sparms.save_simparms( fname );
825 }
826 
827 // Get a speed step from an XML portion
828 void US_SimulationParameters::speedstepFromXml( QXmlStreamReader& xmli,
829  SpeedProfile& spo )
830 {
831  const QString trueStr( " 1YesyesTruetrue" );
832  QXmlStreamAttributes attr = xmli.attributes();
833  QString astr;
834 
835  astr = attr.value( "duration_hrs" ).toString();
836  if ( !astr.isEmpty() )
837  spo.duration_hours = astr.toInt();
838  astr = attr.value( "duration_mins" ).toString();
839  if ( !astr.isEmpty() )
840  spo.duration_minutes = astr.toDouble();
841  astr = attr.value( "delay_hrs" ).toString();
842  if ( !astr.isEmpty() )
843  spo.delay_hours = astr.toInt();
844  astr = attr.value( "delay_mins" ).toString();
845  if ( !astr.isEmpty() )
846  spo.delay_minutes = astr.toDouble();
847  astr = attr.value( "rotorspeed" ).toString();
848  if ( !astr.isEmpty() )
849  spo.rotorspeed = astr.toInt();
850  astr = attr.value( "acceleration" ).toString();
851  if ( !astr.isEmpty() )
852  spo.acceleration = astr.toInt();
853  astr = attr.value( "accelerflag" ).toString();
854  if ( !astr.isEmpty() )
855  spo.acceleration_flag = ( trueStr.indexOf( astr ) > 0 );
856  astr = attr.value( "scans" ).toString();
857  if ( !astr.isEmpty() )
858  spo.scans = astr.toInt();
859  astr = attr.value( "w2tfirst" ).toString();
860  if ( !astr.isEmpty() )
861  spo.w2t_first = astr.toDouble();
862  astr = attr.value( "w2tlast" ).toString();
863  if ( !astr.isEmpty() )
864  spo.w2t_last = astr.toDouble();
865  astr = attr.value( "timefirst" ).toString();
866  if ( !astr.isEmpty() )
867  spo.time_first = astr.toInt();
868  astr = attr.value( "timelast" ).toString();
869  if ( !astr.isEmpty() )
870  spo.time_last = astr.toInt();
871 
872  // MWL enhancements
873  astr = attr.value( "set_speed" ).toString();
874  if ( !astr.isEmpty() )
875  spo.set_speed = astr.toInt();
876  astr = attr.value( "avg_speed" ).toString();
877  if ( !astr.isEmpty() )
878  spo.avg_speed = astr.toDouble();
879  astr = attr.value( "speed_stddev" ).toString();
880  if ( !astr.isEmpty() )
881  spo.speed_stddev = astr.toDouble();
882 }
883 
884 // Write a speed step to an XML stream
885 void US_SimulationParameters::speedstepToXml( QXmlStreamWriter& xmlo,
886  SpeedProfile* spi )
887 {
888  xmlo.writeStartElement( "speedstep" );
889  xmlo.writeAttribute ( "rotorspeed",
890  QString::number( spi->rotorspeed ) );
891  xmlo.writeAttribute ( "scans",
892  QString::number( spi->scans ) );
893  xmlo.writeAttribute ( "timefirst",
894  QString::number( spi->time_first ) );
895  xmlo.writeAttribute ( "timelast",
896  QString::number( spi->time_last ) );
897  xmlo.writeAttribute ( "w2tfirst",
898  QString::number( spi->w2t_first ) );
899  xmlo.writeAttribute ( "w2tlast",
900  QString::number( spi->w2t_last ) );
901  xmlo.writeAttribute ( "duration_hrs",
902  QString::number( spi->duration_hours ) );
903  xmlo.writeAttribute ( "duration_mins",
904  QString::number( spi->duration_minutes ) );
905  xmlo.writeAttribute ( "delay_hrs",
906  QString::number( spi->delay_hours ) );
907  xmlo.writeAttribute ( "delay_mins",
908  QString::number( spi->delay_minutes ) );
909  xmlo.writeAttribute ( "acceleration",
910  QString::number( spi->acceleration ) );
911  xmlo.writeAttribute ( "accelerflag",
912  ( spi->acceleration_flag ? "1" : "0" ) );
913 
914  // Possible MWL enhancements
915  if ( spi->set_speed > 0 )
916  {
917  xmlo.writeAttribute ( "set_speed",
918  QString::number( spi->set_speed ) );
919  xmlo.writeAttribute ( "avg_speed",
920  QString::number( spi->avg_speed ) );
921  xmlo.writeAttribute ( "speed_stddev",
922  QString::number( spi->speed_stddev ) );
923  }
924 
925  xmlo.writeEndElement (); // speedstep
926 }
927 
928 // Get all speed steps for an experiment from the database
930  QVector< SpeedProfile >& sps )
931 {
932  int nspeeds = 0;
933  sps.clear();
934 
935  if ( dbP == NULL || expID < 1 )
936  return nspeeds;
937 
938 int dbg_level=US_Settings::us_debug();
939  QString idExp = QString::number( expID );
940  QStringList query;
941  query << "all_speedsteps" << idExp;
942 
943  dbP->query( query );
944  while( dbP->next() )
945  {
946  SpeedProfile spo;
947  int sspeedID = dbP->value( 0 ).toInt();
948  spo.scans = dbP->value( 1 ).toInt();
949  spo.duration_hours = dbP->value( 2 ).toInt();
950  spo.duration_minutes = dbP->value( 3 ).toDouble();
951  spo.delay_hours = dbP->value( 4 ).toInt();
952  spo.delay_minutes = dbP->value( 5 ).toDouble();
953  spo.rotorspeed = dbP->value( 6 ).toInt();
954  spo.acceleration = dbP->value( 7 ).toInt();
955  QString aflag = dbP->value( 8 ).toString();
956  spo.acceleration_flag = ( aflag.isEmpty() || aflag == "1" );
957  spo.w2t_first = dbP->value( 9 ).toDouble();
958  spo.w2t_last = dbP->value( 10 ).toDouble();
959  spo.time_first = dbP->value( 11 ).toInt();
960  spo.time_last = dbP->value( 12 ).toInt();;
961  spo.set_speed = dbP->value( 13 ).toInt();;
962  spo.avg_speed = dbP->value( 14 ).toDouble();;
963  spo.speed_stddev = dbP->value( 15 ).toDouble();;
964  sps << spo;
965  nspeeds++;
966 DbgLv(1) << "SP:ssFromDB: speedstep" << nspeeds << "id" << sspeedID;
967  }
968 
969  return nspeeds;
970 }
971 
972 // Upload a speed step for an experiment to the database
974  SpeedProfile* spi )
975 {
976 int dbg_level=US_Settings::us_debug();
977 DbgLv(1) << "SP:ssToDB: dbP expid spi" << dbP << expID << spi;
978  int sstepID = -1;
979 
980  if ( dbP == NULL || expID < 0 || spi == NULL )
981  return sstepID;
982 
983  QString idExp = QString::number( expID );
984  QStringList query;
985  query << "new_speedstep" << idExp
986  << QString::number( spi->scans )
987  << QString::number( spi->duration_hours )
988  << QString::number( spi->duration_minutes )
989  << QString::number( spi->delay_hours )
990  << QString::number( spi->delay_minutes )
991  << QString::number( spi->rotorspeed )
992  << QString::number( spi->acceleration )
993  << QString( spi->acceleration_flag ? "1" : "0" )
994  << QString::number( spi->w2t_first )
995  << QString::number( spi->w2t_last )
996  << QString::number( spi->time_first )
997  << QString::number( spi->time_last )
998  << QString::number( spi->set_speed )
999  << QString::number( spi->avg_speed )
1000  << QString::number( spi->speed_stddev );
1001  dbP->statusQuery( query );
1002  sstepID = dbP->lastInsertID();
1003 DbgLv(1) << "SP:ssToDB: speedstep" << sstepID << dbP->lastError();
1004 DbgLv(1) << "SP:ssToDB: w2t" << spi->w2t_first << spi->w2t_last
1005  << QString::number(spi->w2t_first) << QString::number(spi->w2t_last);
1006 
1007  return sstepID;
1008 }
1009 
1010 // Debug print
1012 {
1013  qDebug() << "Sim parms Dump";
1014  qDebug() << "Mesh radius size:" << mesh_radius.size();
1015  qDebug() << "Simpoints :" << simpoints;
1016  qDebug() << "Mesh Type :" << meshType;
1017  qDebug() << "Grid Type :" << gridType;
1018  qDebug() << "Radial Res :" << radial_resolution;
1019  qDebug() << "Meniscus :" << meniscus;
1020  qDebug() << "Bottom Pos :" << bottom_position;
1021  qDebug() << "Bottom :" << bottom;
1022  qDebug() << "Temperature :" << temperature;
1023  qDebug() << "Random noise :" << rnoise;
1024  qDebug() << "Time Inv Noise :" << tinoise;
1025  qDebug() << "Radial Inv Noise:" << rinoise;
1026  qDebug() << "Band Forming :" << band_forming;
1027  qDebug() << "Band Volume :" << band_volume;
1028  qDebug() << "Rotor Calibr.ID :" << rotorCalID;
1029  qDebug() << "Rotor Coeffs :" << rotorcoeffs[ 0 ] << rotorcoeffs[ 1 ];
1030  qDebug() << "CP Sector :" << cp_sector;
1031  qDebug() << "CP Pathlength :" << cp_pathlen;
1032  qDebug() << "CP Angle :" << cp_angle;
1033  qDebug() << "CP Width :" << cp_width;
1034 
1035  for ( int i = 0; i < speed_step.size(); i++ )
1036  {
1037  qDebug() << " Step" << i;
1038  qDebug() << " Duration Hours" << speed_step[ i ].duration_hours;
1039  qDebug() << " Duration Mins " << speed_step[ i ].duration_minutes;
1040  qDebug() << " Delay Hours " << speed_step[ i ].delay_hours;
1041  qDebug() << " Delay Mins " << speed_step[ i ].delay_minutes;
1042  qDebug() << " Scans " << speed_step[ i ].scans;
1043  qDebug() << " Acceleration " << speed_step[ i ].acceleration;
1044  qDebug() << " Rotor Speed " << speed_step[ i ].rotorspeed;
1045  qDebug() << " Accel Flag " << speed_step[ i ].acceleration_flag;
1046  qDebug() << " Omega2t First " << speed_step[ i ].w2t_first;
1047  qDebug() << " Omega2t Last " << speed_step[ i ].w2t_last;
1048  qDebug() << " Time First " << speed_step[ i ].time_first;
1049  qDebug() << " Time Last " << speed_step[ i ].time_last;
1050  qDebug() << " Set Speed " << speed_step[ i ].set_speed;
1051  qDebug() << " Average Speed " << speed_step[ i ].avg_speed;
1052  qDebug() << " Speed StdDev " << speed_step[ i ].speed_stddev;
1053  }
1054 }
1055