Ksetiwatch API Documentation


seticontainer.cpp

Go to the documentation of this file.
00001 /***************************************************************************/
00020 #include <math.h>
00021 #include <errno.h>
00022 #include <sys/file.h>
00023 #include <sys/types.h>
00024 #include <signal.h>
00025 #include <stdio.h>
00026 #include <ctype.h>
00027 
00028 #include <qfile.h>
00029 #include <qfileinfo.h>
00030 #include <qdatetime.h>
00031 #include <qtextstream.h>
00032 
00033 #include "seticontainer.h"
00034 
00035 // needed to prevent rounding errors when comparing doubles
00036 #define DIGITS (double)1.0e-6
00037 
00038 /*------------------------------------------------------------------------ */
00039 SetiContainer::SetiContainer(const QString& dir, int refresh)
00040 {
00041 // store refresh interval in ms
00042 refreshIval   = refresh*1000;
00043 
00044 // set the current directory and initialize everything
00045 setDirectory(dir);
00046 
00047 // start the timer in order to periodically refresh the data
00048 refTimer = startTimer(refreshIval);
00049 
00050 // start timers that check periodically the state of the client
00051 sttTimer1 = startTimer(500);            // every 500 or 2500 ms
00052 sttTimer2 = startTimer(120000);         // every 2 minutes
00053 }
00054 
00055 /*------------------------------------------------------------------------ */
00056 SetiContainer::~SetiContainer()
00057 {
00058 }
00059 
00060 /*------------------------------------------------------------------------ */
00061 void SetiContainer::setDirectory(const QString& dir)
00062 {
00063 // make a back-up
00064 setiDirectory = dir;
00065 
00066 // read the version number of the client
00067 sahVersion = readClientVersion();
00068 // returning zero means that the version file couldn't be found
00069 versionRead = false;
00070 if(sahVersion > 0)
00071   versionRead = true;
00072 
00073 stfFileName = dir + "/state.sah";
00074 wufFileName = dir + "/work_unit.sah";
00075 uifFileName = dir + "/user_info.sah";
00076 rsfFileName = dir + "/result.sah";
00077 rhdFileName = dir + "/result_header.sah";
00078 wtpFileName = dir + "/wtemp.sah";
00079 
00080 // initialize all structures and read new data
00081 initAllData();
00082 
00083 // initialize oldProgress variable for passive monitoring
00084 oldProgress = stfData.prog;
00085 
00086 // reset client state and pid
00087 cltState  = Stopped;
00088 cltPid    = 0;
00089 localClt  = false;
00090 fastCheck = true;
00091 }
00092 
00093 /*------------------------------------------------------------------------ */
00094 void SetiContainer::initAllData(bool sig)
00095 {
00096 // fill all file data members with zeros
00097 initStateFileData();
00098 initWorkUnitData();
00099 initUserInfoData();
00100 
00101 // clear the timestamps
00102 stfTimeStamp = QString::null;
00103 uifTimeStamp = QString::null;
00104 wufTimeStamp = QString::null;
00105 pidTimeStamp = QString::null;
00106 
00107 // read all data
00108 updateSahData(sig);
00109 }
00110 
00111 /*------------------------------------------------------------------------ */
00112 void SetiContainer::setRefreshInterval(int refresh)
00113 {
00114 refreshIval = refresh*1000; // in ms
00115 
00116 // restart the timer with the new refresh interval
00117 killTimer(refTimer);
00118 refTimer = startTimer(refreshIval);
00119 }
00120 
00121 /*------------------------------------------------------------------------ */
00122 void SetiContainer::timerEvent(QTimerEvent* e)
00123 {
00124 if(e->timerId() == refTimer)
00125   updateSahData();
00126 else if(e->timerId() == sttTimer2)
00127   checkClientStatePassive();
00128 else if(e->timerId() == sttTimer1)
00129   {
00130   bool oldFastCheck = fastCheck;
00131   if((int)cpuTime() > 600 && (int)remainingTime() > 600)
00132     fastCheck = false;
00133   else
00134     fastCheck = true;
00135   if(fastCheck != oldFastCheck)
00136     {
00137     //qDebug("SetiContainer (%s): CPU Time=%d, remaining Time=%d, status=%d",
00138     //       (const char*)directory(), (int)cpuTime(), (int)remainingTime(),
00139     //       (int)fastCheck);
00140     killTimer(sttTimer1);
00141     if(fastCheck)
00142       sttTimer1 = startTimer(500);
00143     else
00144       sttTimer1 = startTimer(2500);
00145     }
00146   checkClientState();
00147   }
00148 }
00149 
00150 /*------------------------------------------------------------------------ */
00151 int SetiContainer::updateSahData(bool sig)
00152 {
00153 int err;
00154 int filesMissing = 0;
00155 
00156 // do this complicated check to avoid disk access as much as possible
00157 if(versionRead == false)
00158   {
00159   sahVersion  = readClientVersion();
00160   if(sahVersion > 0)
00161     versionRead = true;
00162   }
00163 else
00164   {
00165   if(QFile::exists(setiDirectory + "/version.sah") == false &&
00166      QFile::exists(setiDirectory + "/version.txt") == false)
00167     {
00168     sahVersion = 0;
00169     versionRead = false;
00170     }
00171   }
00172 
00173 err = readUserInfoFile(sig);
00174 if(err)
00175   {
00176   filesMissing++;
00177   #ifndef NDEBUG
00178     qDebug("SetiContainer (%s): user_info.sah missing.",
00179            (const char*)directory());
00180   #endif
00181   }
00182 
00183 err = readWorkUnitFile(sig);
00184 if(err)
00185   {
00186   filesMissing++;
00187   #ifndef NDEBUG
00188     qDebug("SetiContainer (%s): work_unit.sah missing.",
00189           (const char*)directory());
00190   #endif
00191   }
00192 
00193 err = readStateFile(sig);
00194 if(err)
00195   {
00196   filesMissing++;
00197   #ifndef NDEBUG
00198     qDebug("SetiContainer (%s): state.sah missing.",
00199           (const char*)directory());
00200   #endif
00201   }
00202 
00203 // all three files are missing, switch to Stopped
00204 if(filesMissing == 3)
00205   {
00206   if(cltState != Stopped)
00207     {
00208     cltState = Stopped;
00209     emit stateChanged(cltState);
00210     }
00211   err = 1;
00212   }
00213 
00214 return(err);
00215 }
00216 
00217 /*------------------------------------------------------------------------ */
00218 int SetiContainer::readSahFile(const QString& file, QStringList& list, const QString& endId)
00219 {
00220 int ret(0);
00221 QFile sah(file);
00222 
00223 // clear the list first
00224 list.clear();
00225 
00226 if(sah.open(IO_ReadOnly))
00227   {
00228   QTextStream t(&sah);
00229   QString s;
00230   while( !t.atEnd() )
00231     {
00232     s = t.readLine();
00233     // if reading a line fails or the eof identifier is found stop here
00234     if (s.isEmpty() || (endId && endId == s)) break;
00235     list.append(s);
00236     }
00237   sah.close();
00238   }
00239 else
00240   ret = 1;
00241 
00242 return(ret);
00243 }
00244 
00245 /*------------------------------------------------------------------------ */
00246 int SetiContainer::readStateFile(bool sig)
00247 {
00248 int ret(0);
00249 
00250 // Return with error if file couldn't be found.
00251 if(exists(SC_StateFile) == false) return(1);
00252 
00253 // Read the time stamp of the file...
00254 QFileInfo fi(stfFileName);
00255 QDateTime dt = QDateTime(fi.lastModified());
00256 QString   ts = dt.toString();
00257 // ...and compare it with the stored one.
00258 if(ts != stfTimeStamp)
00259   {
00260   stfTimeStamp = ts;
00261   ret = readSahFile(stfFileName, stateFile);
00262   // If successfully read, scan the file for the data.
00263   if(ret == 0)
00264     scanStateFile(sig);
00265   }
00266 
00267 return(ret);
00268 }
00269 
00270 /*------------------------------------------------------------------------ */
00271 int SetiContainer::readWorkUnitFile(bool sig)
00272 {
00273 int ret(0);
00274 
00275 // Return with error if file couldn't be found.
00276 if(exists(SC_WorkUnitFile) == false) return(1);
00277 
00278 // Read the time stamp of the file...
00279 QFileInfo fi(wufFileName);
00280 QDateTime dt = QDateTime(fi.lastModified());
00281 QString   ts = dt.toString();
00282 // ...and compare it with the stored one.
00283 if(ts != wufTimeStamp)
00284   {
00285   wufTimeStamp = ts;
00286   ret = readSahFile(wufFileName, workunitFile, "end_seti_header");
00287   // If successfully read, scan the file for the data.
00288   if(ret == 0)
00289     scanWorkUnitData(sig);
00290   }
00291 
00292 return(ret);
00293 }
00294 
00295 /*------------------------------------------------------------------------ */
00296 int SetiContainer::readUserInfoFile(bool sig)
00297 {
00298 int ret(0);
00299 
00300 // Return with error if file couldn't be found.
00301 if(exists(SC_UserInfoFile) == false) return(1);
00302 
00303 // Read the time stamp of the file...
00304 QFileInfo fi(uifFileName);
00305 QDateTime dt = QDateTime(fi.lastModified());
00306 QString   ts = dt.toString();
00307 // ...and compare it with the stored one.
00308 if(ts != uifTimeStamp)
00309   {
00310   uifTimeStamp = ts;
00311   ret = readSahFile(uifFileName, userinfoFile);
00312   // If successfully read, scan the file for the data.
00313   if(ret == 0)
00314     scanUserInfoData(sig);
00315   }
00316 
00317 return(ret);
00318 }
00319 
00320 /*------------------------------------------------------------------------ */
00321 QString SetiContainer::readEntry(int sah, const QString& e)
00322 {
00323 QString val;
00324 
00325 switch(sah)
00326   {
00327   case SC_StateFile:
00328     val = readEntry(stfFileName, e);
00329     break;
00330   case SC_UserInfoFile:
00331     val = readEntry(uifFileName, e);
00332     break;
00333   case SC_WorkUnitFile:
00334     val = readEntry(wufFileName, e);
00335     break;
00336   case SC_ResultFile:
00337     val = readEntry(rsfFileName, e);
00338     break;
00339   default:
00340     val = QString::null;
00341     break;
00342   }
00343 
00344 return(val);
00345 }
00346 
00347 
00348 /*------------------------------------------------------------------------ */
00349 QString SetiContainer::readEntry(const QString& fn, const QString& e)
00350 {
00351 QString v = QString::null;
00352 QString l,s;
00353 int eq(-1);
00354 bool found(false);
00355 QFile sah(fn);
00356 
00357 if(sah.open(IO_ReadOnly))
00358   {
00359   QTextStream t(&sah);
00360   while( !t.eof() )
00361     {
00362     s = t.readLine();
00363     // the next line is to prevent hangs when monitoring NFS directories
00364     // (suggested by Frode Tenneboe)
00365     if (s.isEmpty()) break;
00366     eq = s.find('=');
00367     if(eq != -1)
00368       {
00369       l = s.left(eq);
00370       if(l == e) {found = true; break;}
00371       }
00372     }
00373   if(found && s.length()-eq-1 > 0)
00374     v = s.right( s.length()-eq-1 );
00375   sah.close();
00376   }
00377 
00378 return( v );
00379 }
00380 
00381 /*------------------------------------------------------------------------ */
00382 QString SetiContainer::readEntry(QStringList& list, const QString& e)
00383 {
00384 QString v = QString::null;
00385 QString s;
00386 int pos;
00387 bool found(false);
00388 
00389 QStringList::Iterator it;
00390 for(it=list.begin(); it!=list.end(); ++it)
00391   {
00392   // copy the contents of the iterator to a string
00393   s = (*it);
00394   pos = s.find(e);
00395   // accept the found entry only if it is at position 0
00396   if(pos == 0)
00397     {
00398     found = true;
00399     break;
00400     }
00401   }
00402 
00403 if(found)
00404   {
00405   // find the equal char
00406   pos = s.find('=');
00407   // and take the part to the right
00408   if(pos > 0 && s.length()-pos-1 > 0)
00409     v = s.right(s.length()-pos-1);
00410   }
00411 
00412 return(v);
00413 }
00414 
00415 /*------------------------------------------------------------------------ */
00416 void SetiContainer::initWUScore(WUScore* score)
00417 {
00418 score->spike.power     = 0.0;
00419 score->spike.score     = 0.0;
00420 score->spike.bin       = 0;
00421 score->spike.fft_index = 0;
00422 score->spike.fft_len   = 0;
00423 score->spike.chirprate = 0.0;
00424 score->spike.ra        = 0.0;
00425 score->spike.dec       = 0.0;
00426 score->spike.frequency = 0.0;
00427 score->spike.wu_name   = "";
00428 
00429 score->gaussian.score     = 0.0;
00430 score->gaussian.power     = 0.0;
00431 score->gaussian.bin       = 0;
00432 score->gaussian.chisq     = 0.0;
00433 score->gaussian.true_mean = 0.0;
00434 score->gaussian.sigma     = 0.0;
00435 score->gaussian.fft_index = 0;
00436 score->gaussian.fft_len   = 0;
00437 score->gaussian.chirprate = 0.0;
00438 score->gaussian.ra        = 0.0;
00439 score->gaussian.dec       = 0.0;
00440 score->gaussian.frequency = 0.0;
00441 score->gaussian.wu_name   = "";
00442 for(int i=0;i<64;i++) score->gaussian.data[i] = 0.0;
00443 score->gaussian.data_len  = 0;
00444 
00445 score->pulse.score     = 0.0;
00446 score->pulse.power     = 0.0;
00447 score->pulse.mean      = 0.0;
00448 score->pulse.period    = 0.0;
00449 score->pulse.freq_bin  = 0;
00450 score->pulse.time_bin  = 0;
00451 score->pulse.fft_len   = 0;
00452 score->pulse.chirprate = 0.0;
00453 score->pulse.ra        = 0.0;
00454 score->pulse.dec       = 0.0;
00455 score->pulse.frequency = 0.0;
00456 score->pulse.wu_name   = "";
00457 for(int i=0;i<512;i++) score->pulse.data[i] = 0;
00458 score->pulse.data_len  = 0;
00459 
00460 score->triplet.score      = 0.0;
00461 score->triplet.power      = 0.0;
00462 score->triplet.mean       = 0.0;
00463 score->triplet.period     = 0.0;
00464 score->triplet.bperiod    = 0.0;
00465 score->triplet.tpotind0_0 = 0;
00466 score->triplet.tpotind0_1 = 0;
00467 score->triplet.tpotind1_0 = 0;
00468 score->triplet.tpotind1_1 = 0;
00469 score->triplet.tpotind2_0 = 0;
00470 score->triplet.tpotind2_1 = 0;
00471 score->triplet.freq_bin   = 0;
00472 score->triplet.time_bin   = 0.0;
00473 score->triplet.scale      = 0.0;
00474 score->triplet.fft_len    = 0;
00475 score->triplet.chirprate  = 0.0;
00476 score->triplet.ra         = 0.0;
00477 score->triplet.dec        = 0.0;
00478 score->triplet.frequency  = 0.0;
00479 score->triplet.wu_name    = "";
00480 for(int i=0;i<512;i++) score->triplet.data[i] = 0;
00481 score->triplet.data_len   = 0;
00482 }
00483 
00484 /*------------------------------------------------------------------------ */
00485 void SetiContainer::initStateFileData()
00486 {
00487 stfData.ncfft       = 0;
00488 stfData.cr          = 0.0;
00489 stfData.fl          = 0;
00490 stfData.cpu         = 0.0;
00491 stfData.prog        = 0.0;
00492 stfData.potfreq     = 0;
00493 stfData.potactivity = 0;
00494 stfData.outfilepos  = 0;
00495 initWUScore(&stfData.max);
00496 }
00497 
00498 /*------------------------------------------------------------------------ */
00499 void SetiContainer::initWorkUnitData()
00500 {
00501 wufData.task                = "";
00502 wufData.version             = 0;;
00503 wufData.name                = "";
00504 wufData.data_type           = "";
00505 wufData.data_class          = 0;
00506 wufData.splitter_version    = "";
00507 wufData.start_ra            = 0.0;
00508 wufData.start_dec           = 0.0;
00509 wufData.end_ra              = 0.0;
00510 wufData.end_dec             = 0.0;
00511 wufData.angle_range         = 0.0;
00512 wufData.time_recorded       = "";
00513 wufData.subband_center      = 0.0;
00514 wufData.subband_base        = 0.0;
00515 wufData.subband_sample_rate = 0.0;
00516 wufData.fft_len             = 0;
00517 wufData.ifft_len            = 0;
00518 wufData.subband_number      = 0;
00519 wufData.receiver            = "";
00520 wufData.nsamples            = 0;
00521 wufData.tape_version        = "";
00522 wufData.num_positions       = 0;
00523 wufData.coordinates.clear();
00524 }
00525 
00526 /*------------------------------------------------------------------------ */
00527 void SetiContainer::initUserInfoData()
00528 {
00529 uifData.id               = 0;
00530 uifData.key              = 0;
00531 uifData.email_addr       = "";
00532 uifData.name             = "";
00533 uifData.url              = "";
00534 uifData.country          = "";
00535 uifData.postal_code      = 0;
00536 uifData.show_name        = false;
00537 uifData.show_email       = false;
00538 uifData.venue            = 0;
00539 uifData.register_time    = "";
00540 uifData.last_wu_time     = "";
00541 uifData.last_result_time = "";
00542 uifData.nwus             = 0;
00543 uifData.nresults         = 0;
00544 uifData.total_cpu        = 0.0;
00545 uifData.params_index     = 0;
00546 }
00547 
00548 /*------------------------------------------------------------------------ */
00549 void SetiContainer::scanStateFile(bool sig)
00550 {
00551 QString val;
00552 
00553 val = readEntry(stateFile, "ncfft");
00554 stfData.ncfft = val.toInt();
00555 
00556 val = readEntry(stateFile, "cr");
00557 stfData.cr = val.toDouble();
00558 
00559 val = readEntry(stateFile, "fl");
00560 stfData.fl = val.toInt();
00561 
00562 val = readEntry(stateFile, "cpu");
00563 stfData.cpu = val.toDouble();
00564 
00565 double oldprog = stfData.prog;
00566 val = readEntry(stateFile, "prog");
00567 stfData.prog = val.toDouble();
00568 double diff = fmod(stfData.prog-oldprog, DIGITS);
00569 if(diff > 0.0 && sig)
00570   {
00571   emit progressIncreased();
00572   // switch only to Running if the old progress value is non-zero (to
00573   // prevent a freshly mounted location from automatically entering
00574   // the Running state)
00575   if(cltState != Running && oldprog > 0.0)
00576     {
00577     cltState = Running;
00578     emit stateChanged(cltState);
00579     }
00580   }
00581 if(diff < 0.0 && sig) emit progressDecreased();
00582 
00583 val = readEntry(stateFile, "potfreq");
00584 stfData.potfreq = val.toInt();
00585 
00586 val = readEntry(stateFile, "potactivity");
00587 stfData.potactivity = val.toInt();
00588 
00589 val = readEntry(stateFile, "outfilepos");
00590 stfData.outfilepos = val.toInt();
00591 
00592 scanSpikeData(sig);
00593 scanGaussianData(sig);
00594 scanPulseData(sig);
00595 scanTripletData(sig);
00596 
00597 }
00598 
00599 /*------------------------------------------------------------------------ */
00600 void SetiContainer::scanSpikeData(bool sig)
00601 {
00602 QString val;
00603 
00604 // read the highest peak so far
00605 double oldspike = stfData.max.spike.power;
00606 val = readEntry(stateFile, "bs_power");
00607 stfData.max.spike.power = val.toDouble();
00608 
00609 double diff = fmod(stfData.max.spike.power-oldspike, DIGITS);
00610 if(diff > 0.0)
00611   {
00612   // read the binary value of the highest peak
00613   val = readEntry(stateFile, "bs_bin");
00614   stfData.max.spike.bin = val.toInt();
00615 
00616   // read the corresponding chirp rate of the highest peak
00617   val = readEntry(stateFile, "bs_chirp_rate");
00618   stfData.max.spike.chirprate = val.toDouble();
00619 
00620   // read the fft index of the highest peak
00621   val = readEntry(stateFile, "bs_fft_ind");
00622   stfData.max.spike.fft_index = val.toInt();
00623 
00624   // read the fft length of the highest peak
00625   val = readEntry(stateFile, "bs_fft_len");
00626   stfData.max.spike.fft_len = val.toInt();
00627 
00628   // read the score of the highest peak
00629   val = readEntry(stateFile, "bs_score");
00630   stfData.max.spike.score = val.toDouble();
00631 
00632   stfData.max.spike.wu_name = wuName();
00633 
00634   if(sig) emit newSpike(stfData.max.spike);
00635   }
00636 }
00637 
00638 /*------------------------------------------------------------------------ */
00639 void SetiContainer::scanGaussianData(bool sig)
00640 {
00641 QString val;
00642 
00643 // read the strongest gaussian according to its score value
00644 double oldgaussian = stfData.max.gaussian.score;
00645 val = readEntry(stateFile, "bg_score");
00646 stfData.max.gaussian.score = val.toDouble();
00647 
00648 double diff = fmod(stfData.max.gaussian.score-oldgaussian, DIGITS);
00649 if(diff > 0.0)
00650   {
00651   // read the binary value of the highest gaussian
00652   val = readEntry(stateFile, "bg_bin");
00653   stfData.max.gaussian.bin = val.toInt();
00654 
00655   // read the gaussian power
00656   val = readEntry(stateFile, "bg_power");
00657   stfData.max.gaussian.power = val.toDouble();
00658 
00659   // read the gaussian chi square
00660   val = readEntry(stateFile, "bg_chisq");
00661   stfData.max.gaussian.chisq = val.toDouble();
00662 
00663   // read the fft length of the highest gaussian
00664   val = readEntry(stateFile, "bg_fft_len");
00665   stfData.max.gaussian.fft_len = val.toInt();
00666 
00667   // read the corresponding chirp rate of the highest gaussian
00668   val = readEntry(stateFile, "bg_chirp_rate");
00669   stfData.max.gaussian.chirprate = val.toDouble();
00670 
00671   // read the sigma value of the top Gaussian
00672   val = readEntry(stateFile, "bg_sigma");
00673   stfData.max.gaussian.sigma = val.toDouble();
00674 
00675   // read the mean value of the top Gaussian
00676   val = readEntry(stateFile, "bg_true_mean");
00677   stfData.max.gaussian.true_mean = val.toDouble();
00678 
00679   // read the fft index of the top Gaussian
00680   val = readEntry(stateFile, "bg_fft_ind");
00681   stfData.max.gaussian.fft_index = val.toInt();
00682 
00683   // read the data for the Gaussian graph
00684   scanGaussianGraphData();
00685 
00686   stfData.max.gaussian.wu_name = wuName();
00687 
00688   if(sig) emit newGaussian(stfData.max.gaussian);
00689   }
00690 }
00691 
00692 /*------------------------------------------------------------------------ */
00693 void SetiContainer::scanGaussianGraphData()
00694 {
00695 QString val;
00696 
00697 for(int i=0;i<=63;i++)
00698   {
00699   val = readEntry(stateFile, QString("bg_pot %1").arg(i));
00700   stfData.max.gaussian.data[i] = val.toDouble();
00701   }
00702 stfData.max.gaussian.data_len = 64;
00703 }
00704 
00705 /*------------------------------------------------------------------------ */
00706 void SetiContainer::scanPulseData(bool sig)
00707 {
00708 QString val;
00709 
00710 // read the score of the top pulse
00711 double oldpulse = stfData.max.pulse.score;
00712 val = readEntry(stateFile, "bp_score");
00713 stfData.max.pulse.score = val.toDouble();
00714 
00715 double diff = fmod(stfData.max.pulse.score-oldpulse, DIGITS);
00716 if(diff > 0.0)
00717   {
00718   // read the power of the top pulse
00719   val = readEntry(stateFile, "bp_power");
00720   stfData.max.pulse.power = val.toDouble();
00721 
00722   // read the mean value of the top pulse
00723   val = readEntry(stateFile, "bp_mean");
00724   stfData.max.pulse.mean = val.toDouble();
00725 
00726   // read the period of the top pulse
00727   val = readEntry(stateFile, "bp_period");
00728   stfData.max.pulse.period = val.toDouble();
00729 
00730   // read the chirp rate of the top pulse
00731   val = readEntry(stateFile, "bp_chirp_rate");
00732   stfData.max.pulse.chirprate = val.toDouble();
00733 
00734   // read the freq_bin value of the top pulse
00735   val = readEntry(stateFile, "bp_freq_bin");
00736   stfData.max.pulse.freq_bin = val.toInt();
00737 
00738   // read the time_bin value of the top pulse
00739   val = readEntry(stateFile, "bp_time_bin");
00740   stfData.max.pulse.time_bin = val.toInt();
00741 
00742   // read the fft length of the top pulse
00743   val = readEntry(stateFile, "bp_fft_len");
00744   stfData.max.pulse.time_bin = val.toInt();
00745 
00746   // read the graph data
00747   if(scanPulseGraphData() == false)
00748     debug("Pulse data could not be read.");
00749 
00750   stfData.max.pulse.wu_name = wuName();
00751 
00752   if(sig) emit newPulse(stfData.max.pulse);
00753   }
00754 }
00755 
00756 /*------------------------------------------------------------------------ */
00757 bool SetiContainer::scanPulseGraphData()
00758 {
00759 bool status = false;
00760 int  dl;
00761 
00762 QString buf = readEntry(stateFile, "bp_pot");
00763 dl = readDataString(&stfData.max.pulse.data[0], buf, 512);
00764 if(dl > 0)
00765   {
00766   stfData.max.pulse.data_len = dl;
00767   status = true;
00768   }
00769 
00770 return(status);
00771 }
00772 
00773 /*------------------------------------------------------------------------ */
00774 void SetiContainer::scanTripletData(bool sig)
00775 {
00776 QString val;
00777 
00778 // read the score of the top triplet
00779 double oldtriplet = stfData.max.triplet.score;
00780 val = readEntry(stateFile, "bt_score");
00781 stfData.max.triplet.score = val.toDouble();
00782 
00783 double diff = fmod(stfData.max.triplet.score-oldtriplet, DIGITS);
00784 if(diff > 0.0)
00785   {
00786   // read the power of the top triplet
00787   val = readEntry(stateFile, "bt_power");
00788   stfData.max.triplet.power = val.toDouble();
00789 
00790   // read the mean value of the top pulse
00791   val = readEntry(stateFile, "bt_mean");
00792   stfData.max.triplet.mean = val.toDouble();
00793 
00794   // read the period of the top pulse
00795   val = readEntry(stateFile, "bt_period");
00796   stfData.max.triplet.period = val.toDouble();
00797 
00798   // read the chirp rate of the top pulse
00799   val = readEntry(stateFile, "bt_chirp_rate");
00800   stfData.max.triplet.chirprate = val.toDouble();
00801 
00802   // read the index values
00803   val = readEntry(stateFile, "bt_tpotind0_0");
00804   stfData.max.triplet.tpotind0_0 = val.toInt();
00805   val = readEntry(stateFile, "bt_tpotind0_1");
00806   stfData.max.triplet.tpotind0_1 = val.toInt();
00807   val = readEntry(stateFile, "bt_tpotind1_0");
00808   stfData.max.triplet.tpotind1_0 = val.toInt();
00809   val = readEntry(stateFile, "bt_tpotind1_1");
00810   stfData.max.triplet.tpotind1_1 = val.toInt();
00811   val = readEntry(stateFile, "bt_tpotind2_0");
00812   stfData.max.triplet.tpotind2_0 = val.toInt();
00813   val = readEntry(stateFile, "bt_tpotind2_1");
00814   stfData.max.triplet.tpotind2_1 = val.toInt();
00815 
00816   // read the bperiod value of the top pulse
00817   val = readEntry(stateFile, "bt_bperiod");
00818   stfData.max.triplet.bperiod = val.toDouble();
00819 
00820   // read the freq_bin value of the top pulse
00821   val = readEntry(stateFile, "bt_freq_bin");
00822   stfData.max.triplet.freq_bin = val.toInt();
00823 
00824   // read the time_bin value of the top pulse
00825   val = readEntry(stateFile, "bt_time_bin");
00826   stfData.max.triplet.time_bin = val.toDouble();
00827 
00828   // read the scale of the top pulse
00829   val = readEntry(stateFile, "bt_scale");
00830   stfData.max.triplet.scale = val.toDouble();
00831 
00832   // read the fft length of the top pulse
00833   val = readEntry(stateFile, "bt_fft_len");
00834   stfData.max.triplet.fft_len = val.toInt();
00835 
00836   // read the graph data
00837   if(scanTripletGraphData() == false)
00838     debug("Triplet data could not be read.");
00839 
00840   stfData.max.triplet.wu_name = wuName();
00841 
00842   if(sig) emit newTriplet(stfData.max.triplet);
00843   }
00844 }
00845 
00846 /*------------------------------------------------------------------------ */
00847 bool SetiContainer::scanTripletGraphData()
00848 {
00849 bool status = false;
00850 int  dl;
00851 QString buf;
00852 
00853 buf = readEntry(stateFile, "bt_pot");
00854 dl = readDataString(&stfData.max.triplet.data[0], buf, 512);
00855 if(dl > 0)
00856   {
00857   stfData.max.triplet.data_len = dl;
00858   status = true;
00859   }
00860 
00861 return(status);
00862 }
00863 
00864 /*------------------------------------------------------------------------ */
00865 int SetiContainer::readDataString(unsigned short int data[],
00866                                   QString& str, int cnt)
00867 {
00868 char byte[2];        // stores a byte value
00869 int  i = 0;
00870 
00871 if(!str.isEmpty())
00872   {
00873   QTextStream ts(&str, IO_ReadOnly);
00874   unsigned int val;
00875   while(!ts.atEnd() && i < cnt)
00876     {
00877     ts >> byte[0] >> byte[1];
00878     if(isxdigit(byte[0]) && isxdigit(byte[1]))
00879       sscanf(byte, "%x", &val);
00880     else
00881       break;
00882     data[i] = (unsigned short int)val;
00883     i++;
00884     }
00885   }
00886 
00887 return(i);
00888 }
00889 
00890 /*------------------------------------------------------------------------ */
00891 void SetiContainer::scanUserInfoData(bool sig)
00892 {
00893 QString val;
00894 
00895 // read user id
00896 val = readEntry(userinfoFile, "id");
00897 uifData.id = val.toInt();
00898 
00899 // read the key
00900 val = readEntry(userinfoFile, "key");
00901 uifData.key = val.toInt();
00902 
00903 // read the user's email address
00904 uifData.email_addr = readEntry(userinfoFile, "email_addr");
00905 
00906 // read the user name
00907 uifData.name = readEntry(userinfoFile, "name");
00908 
00909 // read the user's url
00910 uifData.url = readEntry(userinfoFile, "url");
00911 
00912 // read the user's country
00913 uifData.country = readEntry(userinfoFile, "country");
00914 
00915 // read the postal code
00916 val = readEntry(userinfoFile, "postal_code");
00917 uifData.postal_code = val.toInt();
00918 
00919 // show the name?
00920 val = readEntry(userinfoFile, "show_name");
00921 if(val == "yes")
00922   uifData.show_name = true;
00923 else
00924   uifData.show_name = false;
00925 
00926 // show the email address?
00927 val = readEntry(userinfoFile, "show_email");
00928 if(val == "yes")
00929   uifData.show_email = true;
00930 else
00931   uifData.show_email = false;
00932 
00933 // read the venue parameter (whatever it is good for)
00934 val = readEntry(userinfoFile, "venue");
00935 uifData.venue = val.toInt();
00936 
00937 // read the register time
00938 uifData.register_time = readEntry(userinfoFile, "register_time");
00939 
00940 // read last wu time
00941 uifData.last_wu_time = readEntry(userinfoFile, "last_wu_time");
00942 
00943 // read last result time
00944 uifData.last_result_time = readEntry(userinfoFile, "last_result_time");
00945 
00946 // read number of sent wus (not used any more)
00947 val = readEntry(userinfoFile, "nwus");
00948 uifData.nwus = val.toInt();
00949 
00950 // read number of completed wus
00951 val = readEntry(userinfoFile, "nresults");
00952 uifData.nresults = val.toInt();
00953 
00954 // read the total cpu time
00955 val = readEntry(userinfoFile, "total_cpu");
00956 uifData.total_cpu = val.toDouble();
00957 
00958 // read the parameter index value (what's that?)
00959 val = readEntry(userinfoFile, "params_index");
00960 uifData.params_index = val.toInt();
00961 
00962 // finally, send emit a signal to notify others of the change
00963 if(sig) emit updatedUserInfoData();
00964 }
00965 
00966 /*------------------------------------------------------------------------ */
00967 void SetiContainer::scanWorkUnitData(bool sig)
00968 {
00969 QString val;
00970 
00971 // read the task (seti, of course)
00972 wufData.task = readEntry(workunitFile, "task");
00973 
00974 // read the version (of what?)
00975 val = readEntry(workunitFile, "version");
00976 wufData.version = val.toInt();
00977 
00978 // read the name of the wu
00979 wufData.name = readEntry(workunitFile, "name");
00980 
00981 // read the data type
00982 wufData.data_type = readEntry(workunitFile, "data_type");
00983 
00984 // read the data class
00985 val = readEntry(workunitFile, "data_class");
00986 wufData.data_class = val.toInt();
00987 
00988 // read the splitter version
00989 wufData.splitter_version = readEntry(workunitFile, "splitter_version");
00990 
00991 // read the start ra value
00992 val = readEntry(workunitFile, "start_ra");
00993 wufData.start_ra = val.toDouble();
00994 
00995 // read the start dec value
00996 val = readEntry(workunitFile, "start_dec");
00997 wufData.start_dec = val.toDouble();
00998 
00999 // read the end ra value
01000 val = readEntry(workunitFile, "end_ra");
01001 wufData.end_ra = val.toDouble();
01002 
01003 // read the end dec value
01004 val = readEntry(workunitFile, "end_dec");
01005 wufData.end_dec = val.toDouble();
01006 
01007 // read the angle range
01008 val = readEntry(workunitFile, "angle_range");
01009 wufData.angle_range = val.toDouble();
01010 
01011 // read the time recorded
01012 wufData.time_recorded = readEntry(workunitFile, "time_recorded");
01013 
01014 // read the subband center frequency
01015 val = readEntry(workunitFile, "subband_center");
01016 wufData.subband_center = val.toDouble();
01017 
01018 // read the subband base frequency
01019 val = readEntry(workunitFile, "subband_base");
01020 wufData.subband_base = val.toDouble();
01021 
01022 // read the subband sample rate
01023 val = readEntry(workunitFile, "subband_sample_rate");
01024 wufData.subband_sample_rate = val.toDouble();
01025 
01026 // read the fft length
01027 val = readEntry(workunitFile, "fft_len");
01028 wufData.fft_len = val.toInt();
01029 
01030 // read the ifft (?) length
01031 val = readEntry(workunitFile, "ifft_len");
01032 wufData.ifft_len = val.toInt();
01033 
01034 // read the subband number
01035 val = readEntry(workunitFile, "subband_number");
01036 wufData.subband_number = val.toInt();
01037 
01038 // read the receiver's id
01039 wufData.receiver = readEntry(workunitFile, "receiver");
01040 
01041 // read the number of samples
01042 val = readEntry(workunitFile, "nsamples");
01043 wufData.nsamples = val.toInt();
01044 
01045 // read the tape version
01046 wufData.tape_version = readEntry(workunitFile, "tape_version");
01047 
01048 // read the number of sky positions
01049 val = readEntry(workunitFile, "num_positions");
01050 wufData.num_positions = val.toInt();
01051 
01052 // read the coordinates
01053 wufData.coordinates.clear();
01054 if(wufData.num_positions > 0)
01055   {
01056   QString e;
01057   for(int i=0; i<wufData.num_positions; i++)
01058     {
01059     val = readEntry(workunitFile, (e = "coord%1").arg(i));
01060     if(!val.isEmpty())
01061       wufData.coordinates.append(val);
01062     }
01063   }
01064 
01065 // finally, send emit a signal to notify others of the change
01066 if(sig) emit updatedWorkUnitData();
01067 }
01068 
01069 /*------------------------------------------------------------------------ */
01070 int SetiContainer::readClientVersion()
01071 {
01072 int version(0);
01073 
01074 QString versionFile(setiDirectory + "/version.sah");
01075 
01076 if(QFile::exists(versionFile))
01077   {
01078   QString entry = readEntry(versionFile, "major_version");
01079   version = 100*entry.toInt();
01080   entry = readEntry(versionFile, "minor_version");
01081   version += entry.toInt();
01082   }
01083 else if(QFile::exists(setiDirectory + "/version.txt"))
01084   version = 100;
01085 
01086 return(version);
01087 }
01088 
01089 
01090 /*------------------------------------------------------------------------ */
01091 double SetiContainer::progressRate()
01092 {
01093 double prograte = (cpuTime() > 0.0) ? (3600.0/cpuTime())*progress() : 0.0;
01094 return(prograte);
01095 }
01096 
01097 /*------------------------------------------------------------------------ */
01098 double SetiContainer::remainingTime()
01099 {
01100 double timeleft = (progressRate() > 0.0) ?
01101                     3600.0*(100.0 - progress())/progressRate() : 0.0;
01102 return(timeleft);
01103 }
01104 
01105 /*------------------------------------------------------------------------ */
01106 QString SetiContainer::remainingTimeAsString()
01107 {
01108 double tl = remainingTime();
01109 return(convertTime(tl, true));
01110 }
01111 
01112 /*------------------------------------------------------------------------ */
01113 QString SetiContainer::convertTime(double time, bool hms)
01114 {
01115 unsigned int d, h, m, s;
01116 QString t;
01117 
01118 d = static_cast<unsigned int>(time/86400.0);
01119 h = static_cast<unsigned int>(time) % 86400 / 3600;
01120 m = static_cast<unsigned int>(time) % 3600 / 60;
01121 s = static_cast<unsigned int>(time) % 60;
01122 
01123 // display with days?
01124 if( hms || (hms == false && d == 0))
01125   {
01126   h += d*24;
01127   t.sprintf("%u:%02u:%02u", h, m, s);
01128   }
01129 else
01130   {
01131   if(d >= 365)
01132     t.sprintf("%.4f yrs", time/31536000.0);
01133   else
01134     t.sprintf("%ud:%02u:%02u:%02u", d, h, m, s);
01135   }
01136 
01137 return(t);
01138 }
01139 
01140 /*------------------------------------------------------------------------ */
01141 QString SetiContainer::convertRAToString(double ra)
01142 {
01143 int h, m, s;
01144 QString val;
01145 
01146 h = static_cast<int>(ra);
01147 m = static_cast<int>((ra - h)*60);
01148 s = static_cast<int>((ra - h)*3600 - m*60);
01149 val.sprintf("%2d h %02d min %02d s", h, m, s);
01150 
01151 return(val);
01152 }
01153 
01154 /*------------------------------------------------------------------------ */
01155 QString SetiContainer::convertDecToString(double dec)
01156 {
01157 int d, m, s;
01158 QString val;
01159 
01160 d = static_cast<int>(dec);
01161 m = static_cast<int>((dec - d)*60);
01162 s = static_cast<int>((dec - d)*3600 - m*60);
01163 val.sprintf("%2d° %02d' %02d''", d, m, s);
01164 
01165 return(val);
01166 }
01167 
01168 /*------------------------------------------------------------------------ */
01169 QString SetiContainer::timeRecordedString()
01170 {
01171 QString tr = timeRecorded();
01172 
01173 int k = tr.find('(');
01174 int l = tr.find(')');
01175 if(k > -1 && l > -1 && l > k)
01176   tr = tr.mid(k+1, l-k-1);
01177 else
01178   tr = "";
01179 
01180 return(tr);
01181 }
01182 
01183 /*------------------------------------------------------------------------ */
01184 double SetiContainer::averageCPUTime()
01185 {
01186 double avgcpu = (numberOfResults() > 0) ? totalCPUTime()/(double)numberOfResults() : 0.0;
01187 return(avgcpu);
01188 }
01189 
01190 /*------------------------------------------------------------------------ */
01191 QString SetiContainer::lastResultTimeString()
01192 {
01193 QString lrt = lastResultTime();
01194 
01195 int k = lrt.find('(');
01196 int l = lrt.find(')');
01197 if(k > -1 && l > -1 && l > k)
01198   lrt = lrt.mid(k+1, l-k-1);
01199 else
01200   lrt = "";
01201 
01202 return(lrt);
01203 }
01204 
01205 /*------------------------------------------------------------------------ */
01206 QString SetiContainer::registerTimeString()
01207 {
01208 QString rt = registerTime();
01209 
01210 int k = rt.find('(');
01211 int l = rt.find(')');
01212 if(k > -1 && l > -1 && l > k)
01213   rt = rt.mid(k+1, l-k-1);
01214 else
01215   rt = "";
01216 
01217 return(rt);
01218 }
01219 
01220 /*------------------------------------------------------------------------ */
01221 bool SetiContainer::exists(int sah)
01222 {
01223 bool ex;
01224 
01225 switch(sah)
01226   {
01227   case SC_StateFile:
01228     ex = QFile::exists(stfFileName);
01229     break;
01230   case SC_UserInfoFile:
01231     ex = QFile::exists(uifFileName);
01232     break;
01233   case SC_WorkUnitFile:
01234     ex = QFile::exists(wufFileName);
01235     break;
01236   case SC_ResultFile:
01237     ex = QFile::exists(rsfFileName);
01238     break;
01239   case SC_WtempFile:
01240     ex = QFile::exists(wtpFileName);
01241     break;
01242   case SC_ResultHeaderFile:
01243     ex = QFile::exists(rhdFileName);
01244     break;
01245   default:
01246     ex = false;
01247     break;
01248   }
01249 
01250 return(ex);
01251 }
01252 
01253 /*------------------------------------------------------------------------ */
01254 double SetiContainer::teraFlops(double ar, int version)
01255 {
01256 double tf(0.0);
01257 
01258 if(version == 0) version = clientVersion();
01259 
01260 if(version >= 200 && version <= 204)
01261   {
01262   if(ar >= 0.2255 && ar <= 1.1274)
01263     tf = 1.45*pow(ar, -0.0826);
01264   else
01265     tf = 1.34;
01266   }
01267 else if(version >= 300 && version < 303)
01268   {
01269   if(ar < 0.2255)
01270     tf = 2.37;
01271 
01272   if(ar >= 0.2255 && ar <= 1.1274)
01273     tf = 2.58*pow(ar, -0.1531);
01274 
01275   if(ar > 1.1274)
01276     tf = 2.23*pow(ar, -0.0115);
01277   }
01278 else if(version >= 303)
01279   {
01280   if(ar < 0.2255)
01281     tf = 3.54*exp(0.0327*ar);
01282 
01283   if(ar >= 0.2255 && ar <= 1.1274)
01284     tf = 3.74*pow(ar, -0.1075);
01285 
01286   if(ar > 1.1274)
01287     tf = 3.37*pow(ar, -0.0065);
01288   }
01289 else
01290   tf = 1.5;
01291 
01292 return(tf);
01293 }
01294 
01295 /*------------------------------------------------------------------------ */
01296 double SetiContainer::megaFlopsPerSecond()
01297 {
01298 return((10.0*teraFlops(angleRange())*progressRate())/3.6);
01299 }
01300 
01301 /*------------------------------------------------------------------------ */
01302 int SetiContainer::checkClientState()
01303 {
01304 // for delayed switching from Finished to Connecting
01305 static int count = 0;
01306 // make a back-up of the old state
01307 int oldState = cltState;
01308 
01309 if(exists(SC_WtempFile) && !exists(SC_ResultHeaderFile))
01310   {
01311   if(
01312      exists(SC_ResultFile))
01313     {
01314     // Finished
01315     if(isClientRunning())
01316       {
01317       /* This indicates that we can control the client locally, so
01318          store the pid. */
01319       localClt = true;
01320       // Follow the sequence Running->Finished->Connecting
01321       if(oldState == Running || oldState == Stopped)
01322         {
01323         cltState = Finished;
01324         count    = 0;
01325         }
01326       else if(oldState == Finished)
01327         {
01328         // count up to 3 (~1.5 s) until switching to Connecting
01329         count++;
01330         if(count >= 3)
01331           cltState = Connecting;
01332         }
01333       }
01334     else
01335       {
01336       cltPid    = (pid_t)0;
01337       cltState  = Finished;
01338       }
01339     }
01340   else
01341     {
01342     // Loading
01343     // check the state of a local client and switch to stop if it was killed
01344     if(isClientRunning())
01345       {
01346       localClt = true;
01347       cltState = Loading;
01348       }
01349     else
01350       {
01351       if(localClt)
01352         {
01353         cltPid   = (pid_t)0;
01354         cltState = Stopped;
01355         }
01356       else
01357         {
01358         // never switch from Running or Stopped to Loading directly, do at least
01359         // once a Finished
01360         if(oldState == Running || oldState == Stopped)
01361           cltState = Finished;
01362         else
01363           cltState = Loading;
01364         }
01365       }
01366     }
01367   }
01368 else // wtemp.sah doesn't exist
01369   {
01370   switch(cltState)
01371     {
01372     case Finished:
01373     case Loading:
01374     case Connecting:
01375       // only update if a new WU is present
01376       if(exists(SC_WorkUnitFile))
01377         {
01378         // set all entries to zero and read the new data
01379         initAllData(true);
01380         // make sure that the timing data are read the first time
01381         stfData.prog = -1.0;
01382         // switch to Running in any case
01383         cltState = Running;
01384         // notify others that a new WU has arrived
01385         emit newWorkUnit(wufData);
01386         }
01387       break;
01388     case Running:
01389       if(localClt && !isClientRunning())
01390         {
01391         cltState = Stopped;
01392         cltPid   = (pid_t)0;
01393         }
01394       break;
01395     case Stopped:
01396       if(isClientRunning())
01397         {
01398         /* This indicates that we can control the client locally, so
01399            store the pid. */
01400         localClt = true;
01401         if(exists(SC_WorkUnitFile))
01402           cltState = Running;
01403         else
01404           cltState = Connecting;
01405         }
01406       break;
01407     default:
01408       #ifndef NDEBUG
01409         qDebug("SetiContainer (%s): Invalid client state.",
01410                (const