UltraScan III
us_convertio.cpp
Go to the documentation of this file.
1 
3 #include <QDomDocument>
4 
5 #include "us_settings.h"
6 #include "us_db2.h"
7 #include "us_passwd.h"
8 #include "us_convert.h"
9 #include "us_convertio.h"
10 #include "us_experiment.h"
11 #include "us_util.h"
12 
13 // Generic constructor
15 {
16 }
17 
19  QList< US_Convert::TripleInfo >& triples,
20  QString dir,
21  US_DB2* db )
22 {
23  const int channelID = 1;
24  QString error = QString( "" );
25 
26  // Delete all existing solutions and rawData, because we're starting over
27  QStringList q( "delete_rawData" );
28  q << QString::number( ExpData.expID );
29  int status = db->statusQuery( q );
30 
31  if ( status != US_DB2::OK )
32  return( db->lastError() );
33 
34  // Delete links between experiment and solutions
35  q.clear();
36  q << "delete_experiment_solutions"
37  << QString::number( ExpData.expID );
38  status = db->statusQuery( q );
39 
40  if ( status != US_DB2::OK )
41  return( db->lastError() );
42 
43  // Same with cell table
44  q.clear();
45  q << "delete_cell_experiments"
46  << QString::number( ExpData.expID );
47  status = db->statusQuery( q );
48 
49  if ( status != US_DB2::OK )
50  return( db->lastError() );
51 
52  // We assume there are files, because calling program checked
53 
54  // Read all data
55  for ( int trx = 0; trx < triples.size(); trx++ )
56  {
57  US_Convert::TripleInfo* triple = &triples[ trx ];
58  if ( triple->excluded ) continue;
59 
60  // Convert uuid's to long form
61  QString triple_uuidc = US_Util::uuid_unparse(
62  (unsigned char*) triple->tripleGUID );
63 
64  // Verify solutionID
65 qDebug() << "cvio:WrRDB: trx" << trx << "soluGUID"
66  << triple->solution.solutionGUID;
67  QStringList q ( "get_solutionID_from_GUID" );
68  q << triple->solution.solutionGUID;
69  db->query( q );
70 
71  status = db->lastErrno();
72 //qDebug() << "cvio:WrRDB: solID" << triple->solution.solutionID
73 // << "status" << status << US_DB2::NOROWS;
74  triple->solution.solutionID = 0;
75  if ( status == US_DB2::OK )
76  {
77  db->next();
78  triple->solution.solutionID = db->value( 0 ).toInt();
79 //qDebug() << "cvio:WrRDB: solID" << triple->solution.solutionID
80 // << "status" << status << US_DB2::NOROWS;
81  }
82 
83  else if ( status == US_DB2::NOROWS )
84  {
85  // Solution is not in db, so try to add it
86  // figure out channelID later ??
87  int diskStatus = triple->solution.saveToDB( ExpData.expID,
88  channelID,
89  db );
90 
91 //qDebug() << "cvio:WrRDB: dkStat" << diskStatus << US_DB2::NO_SOLUTION;
92  if ( diskStatus == US_DB2::NO_BUFFER )
93  error += "Error processing buffer " +
94  triple->solution.buffer.GUID + '\n' +
95  "Buffer was not found in the database";
96 
97  else if ( diskStatus == US_DB2::NO_ANALYTE )
98  error += "Error processing analyte \n"
99  "An analyte was not found in the database";
100 
101  else if ( diskStatus == US_DB2::NO_SOLUTION )
102  error += "Error processing solution " +
103  triple->solution.solutionGUID + '\n' +
104  "Solution was not found in the database";
105 
106  else if ( diskStatus != US_DB2::OK )
107  error += "Error saving solution to DB " + '\n' +
108  db->lastError();
109 
110  }
111 
112  if ( triple->solution.solutionID == 0 )
113  {
114  // This means that we weren't successful in adding it db
115  error += "Error processing solution " +
116  triple->solution.solutionGUID + '\n' +
117  "Solution was not found in the database";
118 //qDebug() << "cvio:WrRDB: NO SOL in DB";
119  }
120 
121  q.clear();
122  q << "new_rawData"
123  << triple_uuidc
124  << ExpData.label
125  << triple->tripleFilename // needs to be base name only
126  << ExpData.comments
127  << QString::number( ExpData.expID )
128  << QString::number( triple->solution.solutionID )
129  << QString::number( channelID ); // only channel 1 implemented
130 
131  status = db->statusQuery( q );
132  QString staterr = db->lastError();
133  int rawDataID = db->lastInsertID();
134 //qDebug() << "cvio:WrRDB: rawDataID" << rawDataID << "status" << status
135 // << "===" << staterr << "===";
136 
137  if ( status == US_DB2::OK )
138  {
139  // If ok, then let's save the tripleID
140  triples[ trx ].tripleID = rawDataID;
141 
142  // We can also upload the auc data
143  int writeStatus = db->writeBlobToDB( dir + triple->tripleFilename,
144  QString( "upload_aucData" ), rawDataID );
145 //qDebug() << "cvio:WrRDB: wrStat" << writeStatus;
146 
147  if ( writeStatus == US_DB2::ERROR )
148  {
149  error += "Error processing file:\n" +
150  dir + triple->tripleFilename + "\n" +
151  db->lastError() + "\n" +
152  "Could not open file or no data \n";
153  }
154 
155  else if ( writeStatus != US_DB2::OK )
156  {
157  error += "Error returned processing file:\n" +
158  dir + triple->tripleFilename + "\n" +
159  db->lastError() + "\n";
160  }
161  }
162 
163  else
164  {
165  error += "Error returned processing file:\n" +
166  dir + triple->tripleFilename + "\n" +
167  db->lastError() + "\n";
168 //qDebug() << "cvio:WrRDB: new_raw ERR" << error;
169  }
170 
171  // Write cell table record
172  QString cellGUID = US_Util::new_guid();
173  QStringList parts = triple->tripleDesc.split(" / ");
174  QString cell = parts[ 0 ];
175  QString letters("0ABCDEFGH");
176  QString channel = parts[ 1 ];
177  int channelNum = letters.indexOf( channel );
178 //qDebug() << "cvio:WrRDB: chNum" << channelNum;
179  q.clear();
180  q << "new_cell_experiment"
181  << cellGUID
182  << cell
183  << QString::number( channelNum )
184  << QString::number( triple->centerpiece )
185  << QString::number( ExpData.expID );
186  int status = db->statusQuery( q );
187  if ( status != US_DB2::OK )
188  error += "Error returned writing cell record: " + cellGUID + "\n" +
189  status + " " + db->lastError() + "\n";
190 
191  // Associate solution in this triple with experiment
192  q.clear();
193  q << "new_experiment_solution"
194  << QString::number( ExpData.expID )
195  << QString::number( triple->solution.solutionID )
196  << QString::number( channelID );
197  status = db->statusQuery( q );
198 qDebug() << "cvio:WrRDB: newExp id solID chnID" << ExpData.expID
199  << triple->solution.solutionID << channelID;
200  if ( status != US_DB2::OK )
201  {
202  error += QObject::tr( "MySQL error associating experiment %1\n"
203  " with solution %2\n"
204  " code: %3 error: %4\n" )
205  .arg( ExpData.expID ).arg( triple->solution.solutionGUID )
206  .arg( status ).arg( db->lastError() );
207  }
208  }
209 
210  if ( error != QString( "" ) )
211  {
212  // Most likely the data is not in a desirable state in the db,
213  // for instance the raw data record might have been written but
214  // the blob upload failed. So let's delete the experiment and
215  // rawData. That way, the runID has not become tainted and
216  // we can try again.
217  q.clear();
218  q << "delete_experiment"
219  << QString::number( ExpData.expID );
220 
221  int delete_status = db->statusQuery( q );
222 
223  if ( delete_status != US_DB2::OK )
224  {
225  error += "MySQL error deleting experiment "
226  + QString::number( ExpData.expID )
227  + "\n" + db->lastError() + "\n";
228  }
229 
230 //qDebug() << "cvio:WrRDB: OUT *ERR*" << error;
231  return error;
232  }
233 //qDebug() << "cvio:WrRDB: OUT";
234 
235  return( QString( "" ) );
236 }
237 
238 // Function to read the experiment info and binary auc files to disk
239 QString US_ConvertIO::readDBExperiment( QString runID, QString dir,
240  US_DB2* db, QVector< SP_SPEEDPROFILE >& speedsteps )
241 
242 {
243  US_Experiment ExpData; // A local copy of experiment
244  QList< US_Convert::TripleInfo > triples; // A local copy of triples
245 qDebug() << "rDBE: call ExpData.readFromDB";
246  int readStatus = ExpData.readFromDB( runID, db, speedsteps );
247 qDebug() << "rDBE: ss size ss0.sp ss0.avg" << speedsteps.size()
248  << speedsteps[0].rotorspeed << speedsteps[0].avg_speed;
249 
250  if ( readStatus == US_DB2::NO_EXPERIMENT )
251  return( "The current run ID is not found in the database." );
252 
253  else if ( readStatus == US_DB2::ERROR )
254  ; // Didn't find any RI Profile data
255 
256  else if ( readStatus != US_DB2::OK )
257  return( db->lastError() );
258 
259  // Erase auc files in the local directory,
260  // in case the user has messed with it locally
261 qDebug() << "rDBE: remove local auc files";
262  QDir d( dir );
263  QStringList nameFilters = QStringList( "*.auc" );
264  QStringList files = d.entryList( nameFilters,
265  QDir::NoDotAndDotDot | QDir::Files );
266  foreach ( QString file, files )
267  if ( ! d.remove( file ) )
268  qDebug() << "Unable to remove file " << file;
269 
270  // Now read the auc data
271 qDebug() << "rDBE: call readRawDataFromDB";
272  QString status = readRawDataFromDB( ExpData, triples, dir, db );
273  if ( status != QString( "" ) )
274  return status;
275 
276  // Verify that the solution and project files are on disk too
277 qDebug() << "rDBE: call ExpData.project.saveToDisk";
278  ExpData.project.saveToDisk();
279 qDebug() << "rDBE: call solution.saveToDisk (loop)";
280  QString psguid = "";
281 
282  foreach ( US_Convert::TripleInfo triple, triples )
283  {
284  QString csguid = triple.solution.solutionGUID;
285  if ( csguid == psguid ) continue;
286 
287  triple.solution.saveToDisk();
288  psguid = csguid;
289  }
290 
291  // Verify that RI Profile is on the disk too
292 qDebug() << "rDBE: call ExpData.saveRIDisk";
293  if ( ExpData.opticalSystem == "RI" )
294  ExpData.saveRIDisk( runID, dir );
295 
296  // Now try to write the xml file
297 qDebug() << "rDBE: call ExpData.saveToDisk";
298 #if 0
299  QVector< SP_SPEEDPROFILE > sp_dmy;
300  int xmlStatus = ExpData.saveToDisk( triples, ExpData.opticalSystem,
301  runID, dir, sp_dmy );
302 #endif
303  int xmlStatus = ExpData.saveToDisk( triples, ExpData.opticalSystem,
304  runID, dir, speedsteps );
305 
306  if ( xmlStatus == US_Convert::CANTOPEN )
307  {
308  QString writeFile = runID + "."
309  + ExpData.opticalSystem + ".xml";
310  return( "Cannot open write file: " + dir + writeFile );
311  }
312 
313  else if ( xmlStatus == US_Convert::NOXML )
314  ; // Covered in caller error message
315 
316  else if ( xmlStatus != US_Convert::OK )
317  return( "Unspecified error writing xml file." );
318 
319  return( QString( "" ) );
320 }
321 
322 // Function to read the auc files to disk
324  QList< US_Convert::TripleInfo >& triples,
325  QString& dir,
326  US_DB2* db )
327 {
328  // Get the rawDataID's that correspond to this experiment
329 qDebug() << " rRDD: build raw list";
330  QStringList q( "get_rawDataIDs" );
331  q << QString::number( ExpData.expID );
332  db->query( q );
333 
334  QStringList rawDataIDs;
335  QStringList filenames;
336 
337  while ( db->next() )
338  {
339  rawDataIDs << db->value( 0 ).toString();
340  filenames << db->value( 2 ).toString();
341  }
342 
343  if ( rawDataIDs.size() < 1 )
344  return( "There were no auc files found in the database." );
345 
346  // Set working directory and create it if necessary
347  dir = US_Settings::resultDir() + "/" + ExpData.runID;
348 
349  QDir work( US_Settings::resultDir() );
350  work.mkdir( ExpData.runID );
351 
352  // Read the auc files to disk
353 qDebug() << " rRDD: read BlobFromDB (loop)";
354  QString error = QString( "" );
355  for ( int i = 0; i < rawDataIDs.size(); i++ )
356  {
357  QString f = dir + "/" + filenames[ i ];
358  int readStatus = db->readBlobFromDB( f, QString( "download_aucData" ),
359  rawDataIDs[ i ].toInt() );
360 
361  if ( readStatus == US_DB2::ERROR )
362  {
363  error += "Error processing file: " + f + "\n" +
364  "Could not open file or no data \n";
365  }
366 
367  else if ( readStatus != US_DB2::OK )
368  {
369  error += "Error returned processing file: " + f + "\n" +
370  db->lastError() + "\n";
371  }
372  }
373 
374  // If we can't even read the files we should just stop here
375  if ( error != QString( "" ) )
376  return( error );
377 
378  // Now get the centerpiece info
379  QList<cellInfo> cells;
380  q.clear();
381  q << "all_cell_experiments"
382  << QString::number( ExpData.expID );
383  db->query( q );
384  while ( db->next() )
385  {
386  struct cellInfo cell;
387  QString letters("0ABCDEFGH");
388  cell.cellName = db->value( 2 ).toString();
389  cell.channelName = QString( letters[ db->value( 3 ).toInt() ] );
390  cell.centerpieceID = db->value( 4 ).toInt();
391  cells << cell;
392  }
393 
394  int psolID = -1;
395 
396  // Get the other db info and create triples
397 qDebug() << " rRDD: build TripleInfo";
398  triples.clear();
399  for ( int i = 0; i < rawDataIDs.size(); i++ )
400  {
401  US_Convert::TripleInfo triple;
402 
403  q.clear();
404  q << "get_rawData"
405  << rawDataIDs[ i ];
406  db->query( q );
407 
408  if ( db->next() )
409  {
410  QString uuidc = db->value( 0 ).toString();
411  US_Util::uuid_parse( uuidc, (unsigned char*) triple.tripleGUID );
412  // triple.label = db->value( 1 ).toString();
413  triple.tripleFilename = db->value( 2 ).toString();
414  // triple.tripleComments = db->value( 3 ).toString();
415  triple.tripleID = rawDataIDs[ i ].toInt();
416  triple.solution.solutionID = db->value( 5 ).toInt();
417 
418  QStringList part = triple.tripleFilename.split( "." );
419  QString wl;
420  QString runType = part[ 1 ];
421  if ( runType == "WA" )
422  wl = QString::number( part[ 4 ].toDouble() / 1000.0 );
423  else
424  wl = part[ 4 ];
425  triple.tripleDesc = part[ 2 ] + " / " + part[ 3 ] + " / " + wl;
426  triple.excluded = false;
427 
428  // Now try to find the centerpiece ID from the info we grabbed earlier
429  bool found = false;
430  foreach ( struct cellInfo cell, cells )
431  {
432  if ( part[ 2 ] == cell.cellName &&
433  part[ 3 ] == cell.channelName )
434  {
435  found = true;
436  triple.centerpiece = cell.centerpieceID;
437  break;
438  }
439 
440  }
441 
442  if ( ! found )
443  {
444  // if we're here, then it's old data and needs to find the centerpiece
445  // in the old manner, which is to say, always the first one
446  triple.centerpiece = cells[ 0 ].centerpieceID;
447  }
448 
449  int csolID = triple.solution.solutionID;
450 
451  // Try to get more solution info
452  int status = US_DB2::OK;
453 
454  if ( csolID != psolID )
455  {
456  status = triple.solution.readFromDB( csolID, db );
457  psolID = csolID;
458  }
459 
460  if ( status == US_DB2::NO_BUFFER )
461  {
462  // buffer wasn't found
463  triple.solution.buffer.bufferID = -1;
464  triple.solution.buffer.GUID = QString( "" );
465  triple.solution.buffer.description = QString( "" );
466  }
467 
468  else if ( status == US_DB2::NO_ANALYTE )
469  triple.solution.analyteInfo.clear();
470 
471  // save it
472  triples << triple;
473  }
474 
475  else
476  error += "Error processing file: " + filenames[ i ] + "\n" +
477  db->lastError() + "\n";
478  }
479 
480  // Get runType
481  QStringList part = triples[ 0 ].tripleFilename.split( "." );
482  ExpData.opticalSystem = part[ 1 ].toAscii();
483 
484  if ( error != QString( "" ) )
485  return( error );
486 
487  return( QString( "" ) );
488 }
489 
491  QList< US_Convert::TripleInfo >& triples,
492  US_DB2* db )
493 {
494  if ( US_Settings::us_inv_ID() == -1 )
495  return US_DB2::NO_PERSON;
496 
497  ExpData.invID = US_Settings::us_inv_ID();
498 
499  // Get investigator GUID
500  QStringList q( "get_person_info" );
501  q << QString::number( ExpData.invID );
502  db->query( q );
503 
504  if ( db->lastErrno() != US_DB2::OK )
505  {
506  ExpData.invID = 0;
507  ExpData.invGUID = QString( "" );
508  ExpData.name = QString( "" );
509  return US_DB2::NO_PERSON;
510  }
511 
512  // Save updated investigator GUID
513  if ( db->next() )
514  {
515  ExpData.invGUID = db->value( 9 ).toString();
516  ExpData.name = db->value( 1 ).toString() + ", " + db->value( 0 ).toString();
517  }
518 
519  // Check all the other GUID's for format
520  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
521 
522  // operator GUID
523  if ( ! rx.exactMatch( ExpData.operatorGUID ) )
524  return US_DB2::BADGUID;
525 
526  // triple GUID's
527  for ( int trx = 0; trx < triples.size(); trx++ )
528  {
529  if ( triples[ trx ].excluded ) continue;
530 
531  QString uuidc = US_Util::uuid_unparse(
532  (unsigned char*) triples[ trx ].tripleGUID );
533  if ( ! rx.exactMatch( uuidc ) )
534  return US_DB2::BADGUID;
535  }
536 
537  // rotor GUID
538  if ( ! rx.exactMatch( ExpData.rotorGUID ) )
539  return US_DB2::BADGUID;
540 
541  // Ok, GUID's are ok
542 
543  // Check if operator exists
544  q.clear();
545  q << QString( "get_personID_from_GUID" )
546  << QString( ExpData.operatorGUID );
547  db->query( q );
548 
549  if ( db->lastErrno() != US_DB2::OK )
550  {
551  ExpData.operatorID = 0;
552  ExpData.operatorGUID = QString( "" );
553  return US_DB2::NO_PERSON;
554  }
555 
556  // Save updated investigator ID
557  if ( db->next() )
558  ExpData.operatorID = db->value( 0 ).toInt();
559 
560  // Check rotor
561  q.clear();
562  q << QString( "get_rotorID_from_GUID" )
563  << QString( ExpData.rotorGUID );
564  db->query( q );
565 
566  if ( db->lastErrno() != US_DB2::OK )
567  {
568  ExpData.rotorID = 0;
569  ExpData.calibrationID = 0;
570  ExpData.rotorCoeff1 = 0.0;
571  ExpData.rotorCoeff2 = 0.0;
572  ExpData.rotorGUID = QString( "" );
573  ExpData.rotorSerial = QString( "" );
574  ExpData.rotorName = QString( "" );
575  return US_DB2::NO_ROTOR;
576  }
577 
578  // Save updated rotor info
579  if ( db->next() )
580  ExpData.rotorID = db->value( 0 ).toInt();
581  q.clear();
582  q << QString( "get_rotor_info" )
583  << QString::number( ExpData.rotorID );
584  db->query( q );
585  if ( db->next() )
586  {
587  ExpData.rotorGUID = db->value( 0 ).toString();
588  ExpData.rotorName = db->value( 1 ).toString();
589  ExpData.rotorSerial = db->value( 2 ).toString();
590  }
591 
592  // Save calibration info
593  if ( ExpData.calibrationID == 0 ) // In this case, get the first one
594  {
595  q.clear();
596  q << QString( "get_rotor_calibration_profiles" )
597  << QString::number( ExpData.rotorID );
598  db->query( q );
599  if ( db->next() )
600  ExpData.calibrationID = db->value( 0 ).toInt();
601  }
602 
603  // Now get more calibration info
604  ExpData.rotorCoeff1 = 0.0;
605  ExpData.rotorCoeff2 = 0.0;
606  ExpData.rotorUpdated = QDate::currentDate();
607  q.clear();
608  q << QString( "get_rotor_calibration_info" )
609  << QString::number( ExpData.calibrationID );
610  db->query( q );
611  if ( db->next() )
612  {
613  ExpData.rotorCoeff1 = db->value( 4 ).toString().toFloat();
614  ExpData.rotorCoeff2 = db->value( 5 ).toString().toFloat();
615  QStringList dateParts = db->value( 7 ).toString().split( " " );
616  ExpData.rotorUpdated = QDate::fromString( dateParts[ 0 ], "yyyy-MM-dd" );
617  }
618 
619  // Initialize triple GUID's
620  int found = true; // Let's assume we'll find them all
621  for ( int i = 0; i < triples.size(); i++ )
622  {
623  if ( triples[ i ].excluded ) continue;
624 
625  QString uuidc = US_Util::uuid_unparse(
626  (unsigned char*) triples[ i ].tripleGUID );
627  q.clear();
628  q << QString( "get_rawDataID_from_GUID" )
629  << uuidc;
630  db->query( q );
631 
632  int status = db->lastErrno();
633 qDebug() << "iSv: trip" << i << "tGUID" << uuidc
634  << "stat,ok,norow" << status << US_DB2::OK << US_DB2::NOROWS;
635  if ( status == US_DB2::OK )
636  {
637  // Save updated triple ID
638  if ( db->next() )
639  triples[ i ].tripleID = db->value( 0 ).toString().toInt();
640 qDebug() << "iSv: tID" << triples[i].tripleID;
641  }
642 
643  else if ( status == US_DB2::NOROWS )
644  {
645  triples[ i ].tripleID = 0;
646  memset( triples[ i ].tripleGUID, 0, 16 );
647  found = false; // At least one wasn't found in the DB
648  }
649 
650  else // more unlikely errors
651  {
652  qDebug() << "get_rawDataID_from_GUID error: " << db->lastErrno();
653  qDebug() << "triple GUID = " << uuidc;
654  return status;
655  }
656 
657  }
658 
659  if ( ! found ) // Probably we just haven't saved it yet
660  return US_DB2::NO_RAWDATA;
661 
662  return US_DB2::OK ;
663 }