Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

omgexperiment.cpp

Go to the documentation of this file.
00001  /***************************************************************************
00002  *   Copyright (C) 2005 by Tim Sutton   *
00003  *   tim@linfiniti.com   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 //local includes
00022 #include "omgexperiment.h"
00023 #include "omglocality.h" //defines OmgLocalities too!
00024 #include "omgui.h" //ancilliary helper methods
00025 #include "omggraph.h"
00026 #include "omgdataseries.h"
00027 #include <omgversion.h> //software version no e.g. 1.0.6
00028 //QT includes
00029 #include <QFileInfo>
00030 #include <QDir>
00031 #include <QImage>
00032 #include <QDateTime>
00033 #include <QDomDocument>
00034 #include <QDomElement>
00035 #include <QStringList>
00036 #include <QMap>
00037 #include <QMapIterator>
00038 #include <QMutexLocker>
00039 #include <QPainter>
00040 OmgExperiment::OmgExperiment() : QThread(),
00041   mAbortFlag(false),
00042   mWorkDir(""),
00043   mRunningFlag(false)
00044 {
00045   //ensure this experiment has a valid guid     
00046   setGuid();
00047   //default the name to the guid
00048   setName(guid());
00049 }
00050 OmgExperiment::~OmgExperiment()
00051 {
00052   //mCondition.wakeOne();
00053   QVectorIterator<OmgModel *> myIterator(mModelVector);
00054   while ( myIterator.hasNext() )
00055   {
00056     OmgModel *  mypModel=myIterator.next();
00057     delete mypModel;
00058   }
00059   // note the OmgModellerPlugin  pointer should *not* be 
00060   // deleted because its managed by the Omgui utility class!!
00061   wait();
00062 }
00063 
00064 QString OmgExperiment::name()
00065 {
00066   return mName;
00067 }
00068 
00069 void OmgExperiment::setName(QString theName)
00070 {
00071   mName=theName;
00072 }
00073 
00074 
00075 QString OmgExperiment::description()
00076 {
00077   return mDescription;
00078 }
00079 
00080 void OmgExperiment::setDescription(QString theDescription)
00081 {
00082   mDescription=theDescription;
00083 }
00084 
00085 QString OmgExperiment::workDir()
00086 {
00087   return mWorkDir;
00088 }
00089 
00090 void OmgExperiment::setWorkDir(QString theWorkDir)
00091 {
00092   mWorkDir=theWorkDir;
00093   if (!mWorkDir.endsWith(QDir::separator()))
00094   {
00095     mWorkDir += QDir::separator();
00096   }
00097   //now update all models to use this dir
00098   QVectorIterator<OmgModel *> myIterator(mModelVector);
00099   while (myIterator.hasNext())
00100   {
00101     OmgModel * mypModel=myIterator.next();
00102     QString mySubDirName = mypModel->algorithm().name();
00103     mySubDirName.replace(" ","_");
00104     mypModel->setWorkDir(mWorkDir + QDir::separator() 
00105                         + mySubDirName + QDir::separator());
00106   }
00107 }
00108 
00109 void OmgExperiment::addModel(OmgModel * thepModel)
00110 {
00111   emit logMessage(tr("Adding model ") 
00112       + thepModel->algorithm().name() + " : " 
00113       + thepModel->taxonName());
00114 
00115   QString mySubDirName = thepModel->algorithm().name();
00116   mySubDirName.replace(" ","_");
00117   thepModel->setWorkDir(mWorkDir + QDir::separator() 
00118       + mySubDirName + QDir::separator());
00119   mModelVector.push_back(thepModel);
00120 }
00121 
00122 OmgModel * OmgExperiment::getModel(int theModelId)
00123 {
00124   if (theModelId >= 0 && theModelId < mModelVector.count())
00125   {
00126     return mModelVector.at(theModelId);
00127   }
00128   return NULL;
00129 }
00130 
00131 OmgModel * OmgExperiment::getModel(QString theGuid)
00132 {
00133   QVectorIterator<OmgModel *> myIterator(mModelVector);
00134   while (myIterator.hasNext())
00135   {
00136     OmgModel *  mypModel=myIterator.next();
00137     if (mypModel->guid()==theGuid)
00138     {
00139       return mypModel;
00140     }
00141   }
00142   return NULL;
00143 }
00144 
00145 void OmgExperiment::removeModel(QString theGuid)
00146 {
00147   QMutableVectorIterator<OmgModel *> myIterator(mModelVector);
00148   while (myIterator.hasNext())
00149   {
00150     OmgModel *  mypModel=myIterator.next();
00151     if (mypModel->guid()==theGuid)
00152     {
00153       delete mypModel;
00154       myIterator.remove();
00155       return ;
00156     }
00157   }
00158   return ;
00159 }
00160 void OmgExperiment::removeAlgorithm(QString theName)
00161 {
00162   QMutableVectorIterator<OmgModel *> myIterator(mModelVector);
00163   while (myIterator.hasNext())
00164   {
00165     OmgModel *  mypModel=myIterator.next();
00166     if (mypModel->algorithm().name()==theName)
00167     {
00168       delete mypModel;
00169       myIterator.remove();
00170     }
00171   }
00172   return ;
00173 }
00174 void OmgExperiment::removeTaxon(QString theName)
00175 {
00176   QMutableVectorIterator<OmgModel *> myIterator(mModelVector);
00177   while (myIterator.hasNext())
00178   {
00179     OmgModel *  mypModel=myIterator.next();
00180     if (mypModel->taxonName()==theName)
00181     {
00182       delete mypModel;
00183       myIterator.remove();
00184     }
00185   }
00186   return ;
00187 }
00188 void OmgExperiment::run()
00189 {
00190   //A QMutexLocker automatically handles locking and unlocking a mutex
00191   //QMutexLocker myLocker(&mMutex);
00192   mAbortFlag=false;
00193   mRunningFlag=true;
00194   emit logMessage(tr("Experiment started"));
00195   mLastPos=0;
00196   int myTotal=count();
00197   emit experimentMaximum(myTotal);
00198   //set the working directory - all output files will be saved here
00199   if (mWorkDir.isEmpty())
00200   {
00201     emit logMessage(tr("Experiment working directory not defined explicity, defaulting to:"));
00202     mWorkDir = QDir::convertSeparators(Omgui::getModelOutputDir()) 
00203     + QDir::separator() 
00204     + name()
00205     + QDir::separator();
00206     emit logMessage(mWorkDir);
00207   }
00208   //make the working dir for the expreiment
00209   if (!mWorkDir.endsWith(QDir::separator()))
00210   {
00211     mWorkDir += QDir::separator();
00212   }
00213       
00214   QDir myWorkDir( mWorkDir );
00215   if (!myWorkDir.exists())
00216   {
00217     emit logMessage(tr("Experiment working directory does not exist...creating"));
00218     QDir myDir(mWorkDir);
00219     if (!myDir.mkdir(mWorkDir))
00220     {
00221       emit logMessage(tr("Experiment failed to create working directory\n") + mWorkDir );
00222       emit experimentProgress(myTotal);
00223       mRunningFlag=false;
00224       emit experimentStopped();
00225       return;
00226     }
00227     else
00228     {
00229       emit logMessage(tr("Experiment created working directory\n") + mWorkDir );
00230     }
00231   }
00232   emit logMessage(tr("Saving before we start experiment"));
00233   save();
00234   emit logMessage(tr("Experiment saved ") + mWorkDir );
00235   //here we use the new Qt4 java style iterator!
00236   QVectorIterator<OmgModel *> myIterator(mModelVector);
00237   while (myIterator.hasNext() && mAbortFlag==false)
00238   {
00239     OmgModel *  mypModel=myIterator.next();
00240     if (mypModel==NULL)
00241     {
00242       emit logMessage(tr("Model is null is NULL, skipping"));
00243       continue;
00244     }
00245     //if the experiment is being resumed dont bother to
00246     //rerun completed models.
00247     //@TODO allow user to force rerun...
00248     if (mypModel->isCompleted())
00249     {
00250       mLastPos++;
00251       emit experimentProgress(mLastPos);
00252       emit logMessage(tr("Model for ") + mypModel->taxonName() + tr(" already exists, skipping to next job."));
00253       continue;
00254     }
00255     OmgAlgorithm myAlgorithm = mypModel->algorithm();
00256     //under the working dir we store each model output in a subdir based on the alg being used
00257     QString mySubDirName = myAlgorithm.name();
00258     mySubDirName.replace(" ","_");
00259     QDir myDir(mWorkDir + mySubDirName);
00260     if (!myDir.exists())
00261     {
00262       emit logMessage(tr("Algorithm working directory does not exist...creating"));
00263       emit logMessage(mWorkDir + mySubDirName);
00264       QDir mySubDir(mWorkDir);
00265       if (!mySubDir.mkdir(mySubDirName))
00266       {
00267         emit logMessage(tr("Experiment failed to create working directory\n") + mWorkDir + mySubDirName);
00268         mRunningFlag=false;
00269         emit experimentStopped();
00270         return;
00271       }
00272     }
00273     mypModel->setWorkDir(mWorkDir + mySubDirName + QDir::separator());
00274     //set the start time
00275     mypModel->setStartDateTimeStamp(QDateTime::currentDateTime());
00276     mCurrentStatus = tr("Creating model definition for ") + mypModel->taxonName();
00277     QString myModelXml = mpModellerPlugin->createModel(mypModel);
00278     emit logMessage(tr("Model has completed:"));
00279     if (mypModel->hasError())
00280     {
00281       emit logMessage(tr("But has an error!"));
00282       mypModel->setCompleted(false);
00283       mypModel->appendToLog(tr("Model failed to complete the model creation stage"));
00284       // create a shapefile of the localities
00285       // we do this even in failure case so the 
00286       // user can still view
00287       // a map of the localities and perhaps try to 
00288       // discern why a model may have failed etc
00289       QString myShapefileName = mypModel->taxonName();
00290       if (mypModel->toShapefile(mypModel->workDir() + myShapefileName + ".shp"))
00291       {
00292         emit logMessage(tr("Creating shapefile as: ") + 
00293             QString(myShapefileName + ".shp").toLocal8Bit());
00294         mypModel->setShapefileName(myShapefileName + ".shp");
00295       }
00296     }
00297     else
00298     {
00299       emit logMessage(tr("Without errors"));
00300       emit logMessage(tr("Parsing model"));
00301       //store the whole model definition in the model object
00302       // parse the model xml that came back and add the samples and the
00303       // serialised model definition
00304       mypModel->parseModelResult(myModelXml);
00305       emit logMessage(tr("Model parsed"));
00306 
00307       //
00308       // Write the shapefile based on the parsed results
00309       //
00310       QString myShapefileName = mypModel->taxonName();
00311       if (mypModel->toShapefile(mypModel->workDir() + myShapefileName + ".shp"))
00312       {
00313         emit logMessage(tr("Creating shapefile as: ") + 
00314             QString(myShapefileName + ".shp").toLocal8Bit());
00315         mypModel->setShapefileName(myShapefileName + ".shp");
00316       }
00317       //regular check for experiment cancelation
00318       if (mAbortFlag)
00319       {
00320         emit logMessage(tr("Saving Experiment"));
00321         save();
00322         mRunningFlag=false;
00323         emit experimentStopped();
00324         return;
00325       }
00326       //end cancellation check
00327       mCurrentStatus = tr("Projecting model for ") + mypModel->taxonName();
00328       emit logMessage(mCurrentStatus);
00329       mpModellerPlugin->projectModel(mypModel);
00330       //
00331       // Handle model success / failure appropriately
00332       //
00333       mCurrentStatus = tr("Model projection completed for ") + mypModel->taxonName();
00334       if (mypModel->hasError())
00335       {
00336         emit logMessage(tr("Model projection had error!"));
00337         mypModel->setCompleted(false);
00338         mypModel->appendToLog(tr("Model failed to complete the model projection stage"));
00339       }
00340       else
00341       {
00342         emit logMessage(tr("Model projection completed! Post processing..."));
00343         mypModel->postProcess();
00344       }
00345     }
00346     //Im saving experiment each iteration now in case something goes wrong...
00347     emit logMessage(tr("Saving Experiment"));
00348     save();
00349     emit logMessage(tr("Experiment saved"));
00350     emit logMessage(mypModel->taxonName() + " done");
00351     if (mypModel->isCompleted())
00352     {
00353       emit modelCompleted(mypModel->guid());
00354     }
00355     mLastPos++;
00356     // we create teh experiment report every model so the gui can always
00357     // show the latests info
00358     toSummaryHtml(true);//true = force recreate
00359     emit experimentProgress(mLastPos);
00360   }
00361   toSummaryHtml(true);//true = force recreate
00362   //say that all models are done
00363   emit experimentProgress(myTotal);
00364   mCurrentStatus = tr("Experiment completed");
00365   emit logMessage(tr("Experiment stopped"));
00366   mRunningFlag=false;
00367   emit experimentStopped();
00368 }
00369 
00370 void OmgExperiment::save()
00371 {
00372   Omgui::createTextFile(mWorkDir + QDir::separator() + guid() + ".xml" , toXml());
00373 }
00374 
00375 void OmgExperiment::setModellerPlugin(OmgModellerPluginInterface * thePlugin)
00376 {
00377   mpModellerPlugin = thePlugin;
00378 }
00379 
00380 int OmgExperiment::count()
00381 {
00382   return mModelVector.count();
00383 }
00384 
00385 void OmgExperiment::clear()
00386 {
00387   mModelVector.clear();
00388 }
00389 
00390 void OmgExperiment::removeCompleted()
00391 {
00392   int myPos=0;
00393   //here we use the new Qt4 java style iterator!
00394   QVectorIterator<OmgModel *> myIterator(mModelVector);
00395   while (myIterator.hasNext())
00396   {
00397     OmgModel * mypModel=myIterator.next();
00399     if (mypModel->isCompleted())
00400     {
00401       mModelVector.remove(myPos);
00402       delete mypModel;
00403     }
00404     else
00405     {
00406       myPos++;
00407     }
00408   }
00409 }
00410 bool OmgExperiment::isRunning()
00411 {
00412   return mRunningFlag;
00413 }
00414 
00415 bool OmgExperiment::isAborted()
00416 {
00417   return mAbortFlag;
00418 }
00419 
00420 void OmgExperiment::abort()
00421 {
00422   mAbortFlag=true;
00423   mCurrentStatus = tr("Experiment aborting...");
00424 }
00425 
00426 OmgModellerPluginInterface * OmgExperiment::modellerPlugin()
00427 {
00428   return mpModellerPlugin;
00429 }
00430 
00431 
00432 void OmgExperiment::reset()
00433 {
00434   QVectorIterator<OmgModel *> myIterator(mModelVector);
00435   while (myIterator.hasNext())
00436   {
00437     OmgModel * mypModel = myIterator.next();
00438     mypModel->reset();
00439   }
00440 }
00441 
00442 const QString OmgExperiment::toString()
00443 {
00444   QString myString("Experiment details:\n=========================\n\n");
00445   //snazzy new java style iterators for qt4
00446   QVectorIterator<OmgModel *> myIterator(mModelVector);
00447   while (myIterator.hasNext())
00448   {
00449     OmgModel * mypModel = myIterator.next();
00450     myString += mypModel->toString();
00451     myString += "\n --- \n";
00452   }
00453   myString += "\n========================\n";
00454   return myString;
00455 }
00456 QString OmgExperiment::toSummaryHtml(bool theForceFlag) 
00457 {
00458   bool myShowGraphsFlag = false;
00459   if (mWorkDir.isEmpty())
00460   {
00461     mWorkDir  = QDir::convertSeparators(Omgui::getModelOutputDir()) 
00462     + name();
00463   }
00464   //make sure the working dir for the expreiment exists
00465   QDir myWorkDir( mWorkDir );
00466   QString myOutputFileName;
00467   if (!myWorkDir.exists())
00468   {
00469     emit logMessage(tr("Working directory does not exist...html not saved"));
00470     emit logMessage("Working dir: " + mWorkDir);
00471     qDebug("Working dir: " + mWorkDir.toLocal8Bit());
00472     return "";
00473   }
00474   else //save it out to file
00475   {
00476     emit logMessage(tr("Saving experiment report as html"));
00477     myOutputFileName = mWorkDir + QDir::separator() + "experiment_report.html";
00478     if (QFile::exists(myOutputFileName) && !theForceFlag)
00479     {
00480       //if the report already exists and forceflag is not true
00481       //we can just return the cache one from the file system
00482       return myOutputFileName;
00483     }
00484   }
00485 
00486   //
00487   // Now the actual report generation part
00488   //
00489   QString myReport = Omgui::getHtmlHeader();
00490   myReport += getStatsHtml();
00491   if (myShowGraphsFlag)
00492   {
00493     myReport += getGraphsHtml("",theForceFlag);
00494   }
00495   myReport += Omgui::getHtmlFooter();
00496   Omgui::createTextFile(myOutputFileName , myReport);
00497   return myOutputFileName;
00498 } //toSummaryHtml
00499 
00500 QString OmgExperiment::toPrintHtml(bool theForceFlag) 
00501 {
00502  bool myShowGraphsFlag = false;
00503   // this method differes from getSummaryHtml in that toPrintHtml
00504   // does not use file cached data and it will use absolute
00505   // paths for graph image files
00506   QString myReport = getStatsHtml();
00507   if (myShowGraphsFlag)
00508   {
00509     myReport += getGraphsHtml(mWorkDir + QDir::separator(), theForceFlag);
00510   }
00511   return myReport;
00512 }
00513 
00514 QString OmgExperiment::getStatsHtml()
00515 {
00516   int mySuccessCount = 0;
00517   int myFailureCount = 0;
00518   int myNotRunCount = 0;
00519   long myTotalTime = 0; //in seconds
00520   //   alg name, cumulative value
00521   QMap<QString,double>  myAlgorithmSuccessMap;
00522   QMap<QString,double>  myRocScoreMap;
00523   QMap<QString,double>  myAccuracyMap;
00524   QMap<QString,double>  myOmissionMap;
00525   QMap<QString,double>  myCommissionMap;
00526   QMap<QString,double>  myPercentCellsPresentMap;
00527   QMap<QString,double>  myTimeMap; //all times in seconds
00528   QVectorIterator<OmgModel *> myIterator(mModelVector);
00529   while (myIterator.hasNext())
00530   {
00531     OmgModel * mypModel = myIterator.next();
00532     if (!mypModel->isCompleted())
00533     {
00534       if (mypModel->hasError())
00535       {
00536         ++myFailureCount;
00537       }
00538       else
00539       {
00540         ++myNotRunCount;
00541       }
00542     }
00543     else
00544     {
00545       //model ran  to completion
00546       if (mypModel->hasError())
00547       {
00548         ++myFailureCount;
00549       }
00550       else
00551       {
00552         ++mySuccessCount;
00553         int myElapsedTime = mypModel->startDateTimeStamp().secsTo(mypModel->endDateTimeStamp());
00554         //we just need to check of one of the stats exits for this alg
00555         if (myAccuracyMap.contains(mypModel->algorithm().name()))
00556         {
00557           //qDebug("Appending " + mypModel->algorithm().name().toLocal8Bit() 
00558           //    + " to experiment stats");
00559           myAlgorithmSuccessMap[mypModel->algorithm().name()] = 
00560             myAlgorithmSuccessMap.value(mypModel->algorithm().name()) + 1;
00561           myRocScoreMap[mypModel->algorithm().name()] = 
00562             myRocScoreMap.value(mypModel->algorithm().name()) +
00563             mypModel->rocScore();
00564           myAccuracyMap[mypModel->algorithm().name()] = 
00565             myAccuracyMap.value(mypModel->algorithm().name()) +
00566             mypModel->accuracy();
00567           myOmissionMap[mypModel->algorithm().name()] = 
00568             myOmissionMap.value(mypModel->algorithm().name()) +
00569             mypModel->omission();
00570           myCommissionMap[mypModel->algorithm().name()] = 
00571             myCommissionMap.value(mypModel->algorithm().name()) +
00572             mypModel->commission();
00573           myPercentCellsPresentMap[mypModel->algorithm().name()] = 
00574             myPercentCellsPresentMap.value(mypModel->algorithm().name()) +
00575             mypModel->percentCellsPresent();
00576           myTimeMap[mypModel->algorithm().name()] = 
00577             myTimeMap.value(mypModel->algorithm().name()) +
00578             myElapsedTime;
00579 
00580           myTotalTime += myElapsedTime;
00581         }
00582         else
00583         {
00584           //qDebug("Adding " + mypModel->algorithm().name().toLocal8Bit() 
00585           //    + " to experiment stats");
00586           myAlgorithmSuccessMap[mypModel->algorithm().name()] = 1;
00587           myRocScoreMap[mypModel->algorithm().name()] = mypModel->rocScore();
00588           myAccuracyMap[mypModel->algorithm().name()] = mypModel->accuracy();
00589           myOmissionMap[mypModel->algorithm().name()] = mypModel->omission();
00590           myCommissionMap[mypModel->algorithm().name()] = mypModel->commission();
00591           myPercentCellsPresentMap[mypModel->algorithm().name()] =
00592             mypModel->percentCellsPresent();
00593           myTimeMap[mypModel->algorithm().name()] = myElapsedTime;
00594           myTotalTime += myElapsedTime;
00595         }
00596       }
00597     }
00598   }
00599   
00600   QString myString;
00601   myString += "<table width=\"100%\">\n";
00602   myString += "<tr>\n";
00603   myString += "<td>\n";
00604   myString += "<p><img src=\":/om_icon_big.png\"></p>";
00605   myString += "</td>\n";
00606   myString += "<td>\n";
00607   myString += "<p align=\"right\">\n";
00608   myString += "<h1>openModeller Desktop</h1>\n";
00609   myString += tr("openModeller is open source software") + "<br />";
00610   myString += "<a href=\"http://openmodeller.sf.net\">http://openmodeller.sf.net</a><br />";
00611   myString += "<h2>" + tr("Experiment Report") + "</h2>\n";
00612   myString += "<h2>" + Omgui::xmlEncode(mName) + "</h2>\n";
00613   myString += "</p>\n";
00614   myString += "</td>\n";
00615   myString += "</tr>\n";
00616   myString += "</table>\n";
00617   myString += "<h3>" + 
00618               tr("Description")  + "</h3>\n";
00619   myString += "<p>" + Omgui::xmlEncode(mDescription) + "</p>\n";
00620   myString += "<h3 class=\"glossyBlue\">" + 
00621               tr("Summary of experiment")  + "</h3>\n";
00622   myString += "<table width=\"100%\">\n";
00623   myString += "<tr>\n";
00624   myString += "<td></td>";
00625   myString += "<td><b>" + QObject::tr("Score")  + "</b></td>";
00626   myString += "</tr>\n";
00627   myString += "<tr>\n";
00628   myString += "<td>";
00629   myString += "<b>" + tr("Total number of models:") + "</b>"; 
00630   myString += "</td><td>";
00631   myString += QString::number(mModelVector.size()); 
00632   myString += "<td>";
00633   myString += "</tr>\n";
00634   myString += "<tr>\n";
00635   myString += "<td>";
00636   myString += "<b>" + tr("Succesfully completed models:") + "</b> "; 
00637   myString += "</td><td>";
00638   myString += QString::number(mySuccessCount);
00639   myString += "<td>";
00640   myString += "</tr>\n";
00641   myString += "<tr>\n";
00642   myString += "<td>";
00643   myString += "<b>" + tr("Failed models:") + "</b> ";
00644   myString += "</td><td>";
00645   myString += QString::number(myFailureCount);
00646   myString += "<td>";
00647   myString += "</tr>\n";
00648   myString += "<tr>\n";
00649   myString += "<td>";
00650   myString += "<b>" + tr("Models not started:") + "</b> "; 
00651   myString += "</td><td>";
00652   myString += QString::number(myNotRunCount);
00653   myString += "</td>";
00654   myString += "</tr>\n";
00655   myString += "<tr>\n";
00656   myString += "<td>";
00657   myString += "<b>" + tr("Elapsed time for all models (excludes report generation time):") + "</b> "; 
00658   myString += "</td><td>";
00659   myString += Omgui::secondsToString <long> (myTotalTime, Omgui::longTimeForm);
00660   myString += "<td>";
00661   myString += "</tr>\n";
00662   myString += "<tr>\n";
00663   myString += "<td>";
00664   myString += "<b>" + tr("Number of failed models:") + "</b> ";
00665   myString += "</td><td>";
00666   myString += QString::number(myFailureCount);
00667   myString += "<td>";
00668   myString += "</tr>\n";
00669   myString += "</table>\n";
00670   
00671   //print a table summarisng accuracy, ommision and cells predicted for each alg
00672   //@TODO calculate stddev for experiment summary stats too
00673   myString += "<h3 class=\"glossyBlue\">" + tr("Algorithm Scores")  + "</h3>\n";
00674   myString += "<p><table width=\"100%\">\n";
00675   myString += "<tr>\n";
00676   myString += "<td><b>" + QObject::tr("Algorithm") + "</b></td>";
00677   myString += "<td><b>" + QObject::tr("Avg. AUC")  + "</b></td>";
00678   myString += "<td><b>" + QObject::tr("Avg. Accuracy")  + "</b></td>";
00679   myString += "<td><b>" + QObject::tr("Avg. Omission")  + "</b></td>";
00680   myString += "<td><b>" + QObject::tr("Avg. Commission")  + "</b></td>";
00681   myString += "<td><b>" + QObject::tr("Avg. Time")  + "</b></td>";
00682   myString += "</tr>\n";
00683   QStringList myKeys = static_cast<QStringList> (myAccuracyMap.keys());
00684   QStringListIterator myListIterator(myKeys);
00685   while (myListIterator.hasNext())
00686   {
00687     QString myKey = myListIterator.next();
00688     myString += "<tr>\n";
00689     myString += "<td>" + myKey + "</td>";
00690     double myAverageRocScore = myRocScoreMap.value(myKey) / myAlgorithmSuccessMap.value(myKey);
00691     myString += "<td>" + QString::number(myAverageRocScore,'f',3) + "</td>";
00692     double myAverageAccuracy = myAccuracyMap.value(myKey) / myAlgorithmSuccessMap.value(myKey);
00693     myString += "<td>" + QString::number(myAverageAccuracy,'f',3) + "%</td>";
00694     double myAverageOmission = myOmissionMap.value(myKey) / myAlgorithmSuccessMap.value(myKey);
00695     myString += "<td>" + QString::number(myAverageOmission,'f',3) + "%</td>";
00696     double myAverageCommission = myCommissionMap.value(myKey) / myAlgorithmSuccessMap.value(myKey);
00697     if (myAverageCommission < 0)
00698     {
00699       myString += "<td> n/a </td>";
00700     }
00701     else
00702     {
00703       myString += "<td>" + QString::number(myAverageCommission,'f',3) + "%</td>";
00704     }
00705     long myAverageDuration = static_cast<long> (myTimeMap.value(myKey) / myAlgorithmSuccessMap.value(myKey));
00706     myString += "<td>" + Omgui::secondsToString (myAverageDuration,Omgui::shortTimeForm) +  "</td>";
00707     myString += "</tr>\n";
00708   }
00709   myString += "</table>\n";
00710   myString += "</p>\n";
00711   return myString;
00712 }
00713 
00714 QString OmgExperiment::getGraphsHtml(QString theImagePrefix /*=""*/, bool theForceFlag /*=false*/)
00715 {
00716   if (theForceFlag)
00717   {
00718     makeAlgorithmSummaryGraphs( mWorkDir );
00719   }
00720   QString myString = "<table width=\"100%\">";
00721   myString += "<tr><td>";
00722   myString += "<h3>" + tr("Roc Score Summary") + "</h3>";
00723   myString += "</td><td>";
00724   myString += "<h3>" + tr("Accuracy Summary") + "</h3>";
00725   myString += "</td></tr>";
00726   //dummy row for pagination issues with printing
00727   myString += "<tr><td>";
00728   myString += "</td><td>";
00729   myString += "</td></tr>";
00730   //end of dummy row
00731   myString += "<tr><td>";
00732   myString += "<img src=\""  + theImagePrefix +  "roc.png\">";
00733   myString += "</td><td>";
00734   myString += "<img src=\""  + theImagePrefix +  "accuracy.png\">";
00735   myString += "</td></tr>";
00736   myString += "<tr><td>";
00737   myString += "<h3>" + tr("Omission Summary") + "</h3>";
00738   myString += "</td><td>";
00739   myString += "<h3>" + tr("Commission Summary") + "</h3>";
00740   myString += "</td></tr>";
00741   //dummy row for pagination issues with printing
00742   myString += "<tr><td>";
00743   myString += "</td><td>";
00744   myString += "</td></tr>";
00745   //end of dummy row
00746   myString += "<tr><td>";
00747   myString += "<img src=\""  + theImagePrefix +  "omission.png\">";
00748   myString += "</td><td>";
00749   myString += "<img src=\""  + theImagePrefix +  "commission.png\">";
00750   myString += "</td></tr>";
00751   myString += "<tr><td>";
00752   myString += "<h3>" + tr("Percent Cells Present Summary") + "</h3>";
00753   myString += "</td><td>";
00754   myString += "<h3>" + tr("Run Time Summary") + "</h3>";
00755   myString += "</td></tr>";
00756   //dummy row for pagination issues with printing
00757   myString += "<tr><td>";
00758   myString += "</td><td>";
00759   myString += "</td></tr>";
00760   //end of dummy row
00761   myString += "<tr><td>";
00762   myString += "<img src=\""  + theImagePrefix +  "cellspresent.png\">";
00763   myString += "</td><td>";
00764   myString += "<img src=\""  + theImagePrefix +  "time.png\"></p>";
00765   myString += "</td></tr>";
00766   myString += "</table>";
00767   return myString;
00768 } //getGraphsHtml
00769 
00770 QString OmgExperiment::toAlgorithmSummaryHtml(QString theAlgorithmName,bool theForceFlag)
00771 {
00772   QString myWorkDirName = QDir::convertSeparators(Omgui::getModelOutputDir()) 
00773     + QDir::separator() 
00774     + name()
00775     + QDir::separator()
00776     + theAlgorithmName.replace(" ","_")
00777     + QDir::separator();
00778   QString myString = "<table>\n";
00779   unsigned int myColumns=4; //adjus here to control no of cols in output
00780   unsigned int myCurrentColumn=1;
00781   //loop through all the models for this alg and make a nice
00782   //thumbnail gallery
00783   QVectorIterator<OmgModel *> myIterator(mModelVector);
00784   while (myIterator.hasNext())
00785   {
00786     OmgModel * mypModel = myIterator.next();
00787     QString myName = mypModel->algorithm().name().replace(" ","_");; 
00788     //qDebug("Does alg name match?");
00789     //qDebug(myName);
00790     //qDebug(theAlgorithmName);
00791     if (myName != theAlgorithmName)
00792     {
00793       continue;
00794     }
00795     if (myCurrentColumn == 1)
00796     {
00797       myString += "<tr>\n";
00798     }
00799     myString += "<td><img src=\"" + myWorkDirName +
00800       mypModel->thumbnailFileName()+ "\"/></td>\n";
00801     if (myCurrentColumn >= myColumns)
00802     {
00803       myString += "</tr>\n";
00804       myCurrentColumn=0; //will be incremented to 1 in next line...
00805     }
00806     ++myCurrentColumn;
00807   } 
00808   myString += "</table>\n";
00809   //qDebug("Created algorithms report");
00810   return myString;
00811 }
00812 QString OmgExperiment::toTaxonSummaryHtml(QString theTaxonName,bool theForceFlag)
00813 {
00814   QString myWorkDirName = QDir::convertSeparators(Omgui::getModelOutputDir()) 
00815     + QDir::separator() 
00816     + name()
00817     + QDir::separator();
00818   QString myString = "<table>\n";
00819   unsigned int myColumns=4; //adjus here to control no of cols in output
00820   unsigned int myCurrentColumn=1;
00821   //loop through all the models for this taxon and make a nice
00822   //thumbnail gallery
00823   QVectorIterator<OmgModel *> myIterator(mModelVector);
00824   while (myIterator.hasNext())
00825   {
00826     OmgModel * mypModel = myIterator.next();
00827     QString myName = mypModel->taxonName();
00828     //qDebug("Does spp name match?");
00829     //qDebug(myName);
00830     //qDebug(theTaxonName);
00831     if (myName != theTaxonName)
00832     {
00833       continue;
00834     }
00835     if (myCurrentColumn == 1)
00836     {
00837       myString += "<tr>\n";
00838     }
00839     QString myFullThumbnailName = myWorkDirName + 
00840       mypModel->algorithm().name().replace(" ","_") + 
00841       QDir::separator() + mypModel->thumbnailFileName();
00842     QFileInfo myFileInfo(myFullThumbnailName);
00843     if (!myFileInfo.exists())
00844     {
00845       continue;
00846     }
00847     myString += "<td><img src=\"" + myFullThumbnailName + "\"/></td>\n";
00848     if (myCurrentColumn >= myColumns)
00849     {
00850       myString += "</tr>\n";
00851       myCurrentColumn=0; //will be incremented to 1 in next line...
00852     }
00853     ++myCurrentColumn;
00854   } 
00855   myString += "</table>\n";
00856   //qDebug("Created taxon report");
00857   return myString;
00858 }
00859   
00860 //implement the serialiseable interface
00861 QString OmgExperiment::toXml() const
00862 {
00863   QString myOmgVersion = 
00864     QString::number(OMGMAJORVERSION) +
00865     QString::number(OMGMINORVERSION) + 
00866     QString::number(OMGRELEASEVERSION);
00867   QString myString("<Experiment Guid=\"" + guid() + "\" Name=\"" + Omgui::xmlEncode(mName) + "\""
00868                   + " Description=\"" + Omgui::xmlEncode(mDescription) + "\""
00869       + " openModellerDesktopVersion=\"" + myOmgVersion + "\">\n");
00870   myString+=QString("  <Models>\n");
00871   QVectorIterator<OmgModel *> myIterator(mModelVector);
00872   while (myIterator.hasNext())
00873   {
00874     OmgModel * mypModel = myIterator.next();
00875     myString += mypModel->toXml()+"\n";
00876   }
00877   myString+=QString("  </Models>\n");
00878   myString+=QString("</Experiment>\n");
00879   return myString;
00880 }
00881 bool OmgExperiment::fromXml(const QString theXml) 
00882 {
00883   QDomDocument myDocument("mydocument");
00884   myDocument.setContent(theXml);
00885   QDomElement myRootElement = myDocument.firstChildElement("Experiment");
00886   if (myRootElement.isNull())
00887   {
00888     //TODO - just make this a warning
00889     //qDebug("top element could not be found!");
00890     return false;
00891   }
00892   mName = Omgui::xmlDecode(myRootElement.attribute("Name"));
00893   mDescription = Omgui::xmlDecode(myRootElement.attribute("Description"));
00894   setGuid( myRootElement.attribute("Guid") );
00895   //get the models collection
00896   QDomElement myModelsElement= myRootElement.firstChildElement("Models");
00897   //iterate through the nested model elements 
00898   QDomElement myModelElement= myModelsElement.firstChildElement("Model");
00899   while(!myModelElement.isNull()) 
00900   {
00901     //this is needed to test nextSibling is a model element
00902     if (myModelElement.tagName()!="Model")
00903     {
00904       //
00905       // go on to the next element
00906       //
00907       myModelElement = myModelElement.nextSiblingElement();
00908       continue;
00909     }
00910     OmgModel * mypModel = new OmgModel();
00911     //get a textual xml representation of the param tag
00912     QDomDocument myModelDoc("model");
00913     //note we need to do a deep copy here because the
00914     //element is shared otherwise and when we
00915     //reparent it the loop stops after the first node
00916     //as no more siblings are found!
00917     QDomElement myCopy = myModelElement.cloneNode().toElement();
00918     myModelDoc.appendChild(myCopy);
00919     QString myXml = myModelDoc.toString();
00920     //now hand over the xml snippet to the model class to be deserialised
00921     if (mypModel->fromXml(myXml))
00922     {
00923       addModel(mypModel);
00924     }
00925     //
00926     // go on to the next element
00927     //
00928     myModelElement = myModelElement.nextSiblingElement();
00929   }
00930   return true;
00931 }
00932 
00933 void OmgExperiment::makeAlgorithmSummaryGraphs(QString theWorkDir) 
00934 {
00935   //   
00936   //   Iterate through the models and collect stats
00937   //   and add them to QMaps and QLists suitable
00938   //   to be passed to OmgGraph
00939   //   
00940   //   alg name, cumulative value
00941   QMap<QString,QList <double> > myRocScoreMap;
00942   QMap<QString,QList <double> > myAccuracyMap;
00943   QMap<QString,QList <double> > myOmissionMap;
00944   QMap<QString,QList <double> > myCommissionMap;
00945   QMap<QString,QList <double> > myPercentCellsPresentMap;
00946   QMap<QString,QList <double> > myTimeMap;
00947 
00948   QVectorIterator<OmgModel *> myIterator(mModelVector);
00949   while (myIterator.hasNext())
00950   {
00951     OmgModel * mypModel = myIterator.next();
00952     QString myName = mypModel->algorithm().name(); 
00953     
00954     addValueToSummaryGraph(myRocScoreMap,myName,mypModel->rocScore());
00955     addValueToSummaryGraph(myAccuracyMap,myName,mypModel->accuracy());
00956     addValueToSummaryGraph(myOmissionMap,myName,mypModel->omission());
00957     addValueToSummaryGraph(myCommissionMap,myName,mypModel->commission());
00958     addValueToSummaryGraph(myPercentCellsPresentMap,myName,mypModel->percentCellsPresent());
00959     int myElapsedTime = mypModel->startDateTimeStamp().secsTo(mypModel->endDateTimeStamp());
00960     addValueToSummaryGraph(myTimeMap,myName,myElapsedTime);
00961   }
00962 
00963   //
00964   // Convert each QMap now and make it a graph
00965   //
00966   summaryMapToGraph( myRocScoreMap, theWorkDir, "roc" );
00967   summaryMapToGraph( myAccuracyMap, theWorkDir, "accuracy" );
00968   summaryMapToGraph( myOmissionMap, theWorkDir, "omission" );
00969   summaryMapToGraph( myCommissionMap, theWorkDir, "commission" );
00970   summaryMapToGraph( myPercentCellsPresentMap, theWorkDir, "cellspresent" );
00971   summaryMapToGraph( myTimeMap, theWorkDir, "time" );
00972 }
00973 void OmgExperiment::addValueToSummaryGraph(
00974     // alg name                 item no, item value
00975     QMap<QString,QList <double> >  & theMap,
00976     QString theAlgorithmName,
00977     double theValue) 
00978 {
00979   if (!theMap.contains(theAlgorithmName))
00980   {
00981     QList <double>  myList;
00982     //QString myString = "Creating " +
00983     //  theAlgorithmName + " << " +
00984     //  QString::number(1) + "," +
00985     //  QString::number(theValue);
00986     //qDebug (myString);
00987     myList << theValue;
00988     theMap[theAlgorithmName] = myList;
00989   }
00990   else
00991   {
00992     QList <double> myList = 
00993       theMap[theAlgorithmName]; 
00994     //QString myString = "Adding " + 
00995     //  theAlgorithmName + " << " +
00996     //  QString::number(myList.size()+1) + "," +
00997     //  QString::number(theValue);
00998     //qDebug (myString);
00999     myList << theValue;
01000     theMap[theAlgorithmName] = myList;
01001   }
01002 }
01003   
01004 void OmgExperiment::summaryMapToGraph( QMap<QString,QList <double> > &theMap, 
01005               QString theWorkDir, QString theImageSuffix )
01006 {
01007   // create an image to paint on - use image rather than pixmap
01008   // as it can then be used in console only contexts
01009   QImage myImage(350,350,QImage::Format_ARGB32);
01010   myImage.fill(Qt::white);
01011   QPainter myPainter(&myImage);
01012   OmgGraph myGraph(&myPainter);
01013   int myCount=0;
01014   QMapIterator<QString,QList <double> >  myIterator(theMap);
01015   while (myIterator.hasNext())
01016   {
01017     myIterator.next();
01018     //algorithm name
01019     QString myName = myIterator.key();
01020     QList <double> myList = myIterator.value();
01021     OmgDataSeries mySeries;
01022     mySeries.setLabel( myName );
01023     mySeries.setYValuesList( myList );
01024     //mySeries.sortY();
01025     //use a predictable colour
01026     switch (myCount)
01027     {
01028       case 0: mySeries.setFillColor(Qt::red);
01029               break;
01030       case 1: mySeries.setFillColor(Qt::green);
01031               break;
01032       case 2: mySeries.setFillColor(Qt::blue);
01033               break;
01034       case 3: mySeries.setFillColor(Qt::darkMagenta);
01035               break;
01036       case 4: mySeries.setFillColor(Qt::yellow);
01037               break;
01038       case 5: mySeries.setFillColor(Qt::darkRed);
01039               break;
01040       case 6: mySeries.setFillColor(Qt::darkCyan);
01041               break;
01042       case 7: mySeries.setFillColor(Qt::darkGray);
01043               break;
01044       case 8: mySeries.setFillColor(Qt::magenta);
01045               break;
01046       default: mySeries.setFillColor(Omgui::randomColour());
01047     }
01048     mySeries.setLineColor(mySeries.fillColor().lighter());
01049     myGraph.addSeries( mySeries );
01050     ++myCount;
01051   }
01052   myGraph.setVertexLabelsEnabled(false);
01053   myGraph.setGridLinesEnabled(true);
01054   myGraph.setAreaFillEnabled(false);
01055   myGraph.clear();
01056   myGraph.render();
01057   myImage.save(  theWorkDir + QDir::separator() + theImageSuffix + ".png");
01058 }

Generated on Mon Apr 28 15:08:22 2008 for openModellerDesktop by  doxygen 1.4.1-20050210