calculation.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                         calculation.cpp  -  description
00003                              -------------------
00004     begin                : Thu April 28 2005
00005     copyright            : (C) 2005-2006 by Ben Swerts
00006     email                : bswerts@users.sourceforge.net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00019 
00045 
00046 
00047 
00049 
00050 // C++ header files
00051 #include <cassert>
00052 #include <iostream>
00053 
00054 // Qt header files
00055 #include <qapplication.h>
00056 #include <qdir.h>
00057 #include <qdom.h>
00058 #include <qfile.h>
00059 #include <qmessagebox.h>
00060 #include <qprocess.h>
00061 #include <qtimer.h>
00062 #include <qurloperator.h>
00063 #include <qwidget.h>
00064 
00065 // Xbrabo header files
00066 #include "atomset.h"
00067 #include "calculation.h"
00068 #include "crdfactory.h"
00069 #include "domutils.h"
00070 #include "globalbase.h"
00071 #include "paths.h"
00072 
00076 
00078 Calculation::Calculation(AtomSet* atomset, QWidget* parent, const char* name) : QObject(parent, name),
00079 atoms(atomset),
00080 parentWidget(parent),
00081 braboInput(QStringList()),
00082 stockInput(QStringList()),
00083 relaxInput(QStringList()),
00084 basissetList(QStringList()),
00085 startVectorFile(QString::null),
00086 atdensFile(QString::null),
00087 affUpdateFreq(0),
00088 calculationType(0),
00089 crystalType(0),
00090 updateBraboInput(true),
00091 updateStockInput(false),
00092 updateRelaxInput(false),
00093 doBasissetCheck(true),
00094 copyAtdens(false),
00095 calcRunning(false),
00096 calcPaused(false),
00097 calcName(QString::null),
00098 calcDir(QString::null),
00099 calcProcess(0),
00100 stopRequested(false),
00101 backupFrequency(0),
00102 calcModified(false),
00103 calcError(NoError),
00104 calcContinuable(false)
00106 {
00107   assert(atomset != 0);
00108 }
00109 
00111 Calculation::~Calculation()
00113 {
00114 
00115 }
00116 
00118 bool Calculation::start()
00121 {
00123   if(calcRunning)
00124   {
00125     if(!calcPaused)
00126     {
00127       //QMessageBox::warning(parentWidget, tr("Start Calculation") , tr("Only 1 calculation can be run at a time"));
00128       return false;
00129     }
00130     else
00131     {
00132       calcPaused = false;
00133       doNextStep();
00134       return true;
00135     }
00136   }
00138   assert(!braboInput.isEmpty());
00140   if(calculationType == GlobalBase::GeometryOptimization)
00141     assert(!relaxInput.isEmpty());
00143   if(doBasissetCheck && !checkBasissets())
00144     return false;
00145 
00147   if(!checkExecutables())
00148     return false;
00149 
00151   if(!makeDirCurrent(calcDir, tr("Start Calculation")))
00152     return false;
00153 
00155   if(!copyStartVector())
00156     return false;
00157 
00159   bool calcContinue = false;
00160   QFile fileCRD(calcName + ".crd");
00161   if(calculationType == GlobalBase::GeometryOptimization && calcContinuable && fileCRD.exists())
00162   {
00163     // the optimization can possibly be continued from the current or previous cycle
00164     calcContinue = QMessageBox::question(parentWidget, tr("Geometry optimization"), 
00165       tr("The geometry optimization can possibly be continued."), //\nYou can choose to try to continue from the current cycle\nor the previous one."), 
00166       tr("Current cycle"), tr("Restart")) == 0;
00167   }
00168   if(!calcContinue && CrdFactory::writeToFile(atoms, calcName + ".crd", calcXF) != CrdFactory::OK)
00169   {
00170     QMessageBox::warning(parentWidget, tr("Start Calculation"), tr("Unable to write the initial coordinates"));
00171     return false;
00172   }
00173 
00175   if(calculationType == GlobalBase::GeometryOptimization)
00176   {
00177     QFile optcrd(calcName + ".c00");
00178     if(optcrd.exists())
00179     {
00180       if(!optcrd.remove())
00181       {
00182         QMessageBox::warning(parentWidget, tr("Start calculation"), tr("The existing .c00 file could not be removed."));
00183         return false;
00184       }
00185     }
00186   }
00187   
00190   QDir dir(calcDir);
00191   QStringList files = dir.entryList(calcName + "_*"); // all files named molecule_* 
00192   QFile file;
00193   for(QStringList::Iterator it = files.begin(); it != files.end(); it++)
00194   {
00195     file.setName(*it);
00196     file.remove();
00197   }
00198 
00200   // NOTE: after BRABO, STOCK and (MAFF,RELAX) can execute in parallel
00201   // NOTE: Always add all steps and decide whether or not to run them in doNextStep
00202   calculationSteps.clear();
00203   calculationSteps.push_back(BRABO);
00204   calculationSteps.push_back(STOCK);
00205   calculationSteps.push_back(UPDATE);
00206   if(calculationType == GlobalBase::GeometryOptimization)
00207   {
00208     calculationSteps.push_back(MAFF);
00209     calculationSteps.push_back(CNVRTAFF);
00210     calculationSteps.push_back(RELAX);
00211   }
00212   // add this step last
00213   calculationSteps.push_back(NEW_CYCLE);
00214 
00215   stopRequested = false;  
00216   calcRunning = true;
00217   currentCycle = 0;
00218   calcError = NoError;
00219 
00220   // start the calculation by invoking the dispatcher
00221   doNextStep();
00222   return true;
00223 }
00224 
00226 bool Calculation::pause()
00231 {
00232   // return if the calculation is not running
00233   if(!calcRunning)
00234     return false;
00235 
00236   // start if calculation is already paused
00237   if(calcPaused)
00238     return start();
00239 
00240   // return if only 1 step is performed
00241   if(calculationSteps.size() == 2) 
00242     return false;
00243 
00244   calcPaused = true;
00245   setModified();
00246   return true;
00247 }
00248 
00250 bool Calculation::stop()
00256 {
00257   if(!calcRunning)
00258     return false;
00259   
00260   if(calcPaused) // for loading a paused calculation from disk
00261   {
00262     calcRunning = false;
00263     if(calcError == NoError)
00264       calcError = UndefinedError;
00265     doNextStep();
00266     return true;
00267   }
00268 
00269   int result = QMessageBox::information(parentWidget, tr("Stop calculation"), tr("Please specify how the calculation should be stopped."), 
00270                tr("After the current step"), tr("Immediately"), tr("Cancel"), 0, 2);
00271   switch(result)
00272   {
00273     case 0: // stop the calculation after the current step has ended
00274             stopRequested = true; 
00275             setModified();
00276             break;
00277     case 1: // stop the calculation immediately
00278             if(calcProcess != 0)
00279               calcProcess->kill();
00280             calcRunning = false;
00281             if(calcError == NoError)
00282               calcError = ManualStop;
00283             doNextStep();
00284             break;
00285     case 2: // cancel stopping
00286             return false;
00287   }
00288   return true;
00289 }
00290 
00292 void Calculation::setModified(const bool status)
00294 {
00295   if(status && !calcModified)
00296     emit modified();
00297   calcModified = status;
00298 }
00299 
00301 void Calculation::setBraboInput(const QStringList stdInput, const QStringList basissets, const QString startVector, const bool preferStartVector, const unsigned int startVectorSize1, const unsigned int startVectorSize2)
00310 {
00313   if(calcRunning && (calculationType == GlobalBase::SinglePointEnergy || calculationType == GlobalBase::EnergyAndForces))
00314     return;
00315 
00317   if(!stdInput.isEmpty())
00318   {
00319     braboInput = stdInput;
00320     updateBraboInput = true;
00321   }
00322 
00324   if(basissets != basissetList && !basissets.isEmpty())
00325   {
00326     basissetList = basissets;
00327     doBasissetCheck = true;
00328   }
00329 
00331   // - if the calculation is not running, check the validity of any existing startvector
00332   //   with the right name if preferStartVector = true, else use the provided startvector
00333   //   (or none if none is specified)
00334   // - if the calculation already started, only update the startvector if the basisset
00335   //   changed. 
00336   qDebug("setBraboInput: calcRunning = %d, prefer = %d, size1 = %d, size2 = %d",calcRunning, preferStartVector, startVectorSize1, startVectorSize2);
00337   qDebug("               startVector = " + startVector + ", startVectorFile = " + startVectorFile);
00338   if(!calcRunning)
00339   {
00340     if(preferStartVector)
00341     {
00342       QFileInfo fi(calcDir + QDir::separator() + calcName + ".sta");
00343       if(fi.size() == startVectorSize1 || fi.size() == startVectorSize2) // will fail if no filename like this exists
00344         startVectorFile = calcDir + QDir::separator() + calcName + ".sta";
00345       else
00346       {
00347         fi.setFile(startVector);
00348         qDebug("size of " + startVector + " = %d", fi.size());
00349         if(fi.size() == startVectorSize1 || fi.size() == startVectorSize2) // will always return false if startVector is empty
00350           startVectorFile = startVector; 
00351         else
00352           startVectorFile = QString::null; // do not use a starting vector at the next step (initial step here)
00353       }
00354     }
00355     else
00356     {
00357       QFileInfo fi(startVector);
00358       if(fi.size() == startVectorSize1 || fi.size() == startVectorSize2)
00359         startVectorFile = startVector;
00360       else
00361         startVectorFile = QString::null;
00362     }
00363   }
00364   else if(doBasissetCheck)
00365   {
00366     QFileInfo fi(startVectorFile);
00367     if(fi.size() != startVectorSize1 && fi.size() != startVectorSize2)
00368     {
00369       // the calculation is running, the basis set has changed and the
00370       // current starting vector cannot be used anymore.
00371       // WARNING: this does not work when the calculation is doing the first BRABO 
00372       //          call without a starting vector and before the first iteration of
00373       //          the SCF has been completed (thus before a starting vector has been 
00374       //          written). In that case startVectorFile is still empty.
00375       fi.setFile(startVector);
00376       if(fi.size() == startVectorSize1 || fi.size() == startVectorSize2)
00377         startVectorFile = startVector; // use the given start vector 
00378       else
00379         startVectorFile = QString::null; // regenerate the starting vector    
00380     }
00381   }
00382   qDebug("chosen startvector = " + startVectorFile);
00383 }
00384 
00386 void Calculation::setStockInput(const QStringList stin, const QString atdens)
00391 {
00392   if(!stin.isEmpty())
00393   {
00394     stockInput = stin;
00395     updateStockInput = true;
00396   }
00397 
00398   if(!atdens.isEmpty())
00399   {
00400     atdensFile = atdens;
00401     copyAtdens = true;
00402   }
00403 }
00404 
00406 void Calculation::setRelaxInput(const QStringList aff, const QStringList maff, const unsigned int updateFreq, const unsigned int maxSteps, const std::vector<unsigned int>& steps, const std::vector<double>& factors)
00420 {
00421   if(!aff.isEmpty())
00422   {
00423     relaxInput = aff;
00424     updateRelaxInput = true;
00425     maffInput = maff;
00426   }
00427   affUpdateFreq = updateFreq;
00428   if(!steps.empty() && steps.size() == factors.size())
00429   {
00430     scaleSteps.clear();
00431     scaleSteps.reserve(steps.size());
00432     scaleSteps.assign(steps.begin(), steps.end());
00433     scaleFactors.clear();
00434     scaleFactors.reserve(factors.size());
00435     scaleFactors.assign(factors.begin(), factors.end());
00436   }
00437   calcMaxCycle = maxSteps;
00438 }
00439 
00441 void Calculation::setCalculationType(const unsigned int type, const unsigned int buur)
00447 {
00448   if(!calcRunning)
00449   {
00450     calculationType = type;
00451     crystalType = buur;
00452   }
00453 }
00454 
00456 void Calculation::setParameters(const QString name, const QString dir, const bool format)
00458 {
00459   calcName = name;
00460   calcDir = dir;
00461   calcXF = format;
00462 }
00463 
00465 void Calculation::setBackup(const unsigned int freq, const bool brabo, const bool stock, const bool relax, const bool aff, const bool crd)
00467 {
00468   backupFrequency = freq;
00469   if(backupFrequency != 0)
00470   {
00471     backupBrabo = brabo;
00472     backupStock = stock;
00473     backupRelax = relax;
00474     backupAFF = aff;
00475     backupCRD = crd;
00476   }
00477   setModified();
00478 }
00479 
00481 void Calculation::setContinuable(const bool status)
00483 {
00484   calcContinuable = status;
00485 }
00486 
00488 bool Calculation::isRunning() const
00490 {
00491   return calcRunning;
00492 }
00493 
00495 bool Calculation::isPaused() const
00497 {
00498   return calcPaused;
00499 }
00500 
00502 void Calculation::getRefinementParameters(bool& largestCart, bool& magnCart, bool& largestInt, bool& magnInt, bool& largestShift)
00506 {
00507   largestCart = false;
00508   magnCart = false;
00509   largestInt = false;
00510   magnInt = false;
00511   largestShift = false;
00512 
00513   QFile file(calcDir + QDir::separator() + calcName + ".aou");
00514   if(!file.open(IO_ReadOnly))
00515     return;
00516   QTextStream stream(&file);
00517   while(!stream.atEnd())
00518   {
00519     QString line = stream.readLine();
00520     if(line.contains("OK"))
00521     {
00522       if(line.contains("LARGEST CARTESIAN FORCE"))
00523         largestCart = true;
00524       else if(line.contains("MAGNIT. CART. FORCE VEC"))
00525         magnCart = true;
00526       else if(line.contains("LARGEST INTERNAL FORCE"))
00527         largestInt = true;
00528       else if(line.contains("MAGNIT. INT. FORCE VEC"))
00529         magnInt = true;
00530       else if(line.contains("LARGEST SHIFT"))
00531         largestShift = true;
00532     }
00533   }
00534 }
00535 
00537 void Calculation::getAvailableOutputs(std::vector<unsigned int>& cycles, std::vector<bool>& brabo, std::vector<bool>& stock, std::vector<bool>& relax, std::vector<bool>& aff)
00539 {
00540   cycles.clear();
00541   brabo.clear();
00542   stock.clear();
00543   relax.clear();
00544   aff.clear();
00545 
00546   bool out, stou, aou, aff2;
00547   QFile file;
00548   QString prefix = calcDir + QDir::separator() + calcName + "_";
00549   for(unsigned int i = 1; i <= currentCycle; i++)
00550   {
00551     QString prefixCycle = prefix + QString::number(i);
00552     file.setName(prefixCycle + ".out");
00553     out = file.exists();
00554     file.setName(prefixCycle + ".stou");
00555     stou = file.exists();
00556     file.setName(prefixCycle + ".aou");
00557     aou = file.exists();
00558     file.setName(prefixCycle + ".aff");
00559     aff2 = file.exists();
00560     if(out || stou || aou || aff2)
00561     {
00562       // at least one output exists so add a cycle
00563       cycles.push_back(i);
00564       brabo.push_back(out);
00565       stock.push_back(stou);
00566       relax.push_back(aou);
00567       aff.push_back(aff2);
00568     }
00569   }
00570 }
00571 
00573 QStringList Calculation::braboOutput(const unsigned int step)
00576 {
00577   return output(".out", step);
00578 }
00579 
00581 QStringList Calculation::stockOutput(const unsigned int step)
00584 {
00585   return output(".stou", step);
00586 }
00587 
00589 QStringList Calculation::relaxOutput(const unsigned int step)
00592 {
00593   return output(".aou", step);
00594 }
00595 
00597 QStringList Calculation::affOutput(const unsigned int step)
00600 {
00601   return output(".aff", step);
00602 }
00603 
00605 void Calculation::loadCML(const QDomElement* root)
00607 {
00608   const QString prefix = "calculation_";
00609   QDomNode childNode = root->firstChild();
00610   while(!childNode.isNull())
00611   {
00612     if(childNode.isElement() && childNode.toElement().tagName() == "parameter")
00613     {
00614       if(DomUtils::dictEntry(childNode, prefix + "starting_vector"))
00615         DomUtils::readNode(&childNode, &startVectorFile);
00616       else if(DomUtils::dictEntry(childNode, prefix + "update_energy_and_forces"))
00617         DomUtils::readNode(&childNode, &updateBraboInput);
00618       else if(DomUtils::dictEntry(childNode, prefix + "update_stockholder"))
00619         DomUtils::readNode(&childNode, &updateStockInput);
00620       else if(DomUtils::dictEntry(childNode, prefix + "update_geometry_optimization"))
00621         DomUtils::readNode(&childNode, &updateRelaxInput);
00622       else if(DomUtils::dictEntry(childNode, prefix + "check_basissets"))
00623         DomUtils::readNode(&childNode, &doBasissetCheck);
00624       else if(DomUtils::dictEntry(childNode, prefix + "running"))
00625         DomUtils::readNode(&childNode, &calcRunning);
00626       else if(DomUtils::dictEntry(childNode, prefix + "paused"))
00627         DomUtils::readNode(&childNode, &calcPaused);
00628       else if(DomUtils::dictEntry(childNode, prefix + "current_cycle"))
00629         DomUtils::readNode(&childNode, &currentCycle);
00630       else if(DomUtils::dictEntry(childNode, prefix + "error"))
00631         DomUtils::readNode(&childNode, &calcError);
00632       else if(DomUtils::dictEntry(childNode, prefix + "continuable"))
00633         DomUtils::readNode(&childNode, &calcContinuable);
00634       else if(DomUtils::dictEntry(childNode, prefix + "steps"))
00635       {
00636         std::vector<unsigned int> steps;
00637         DomUtils::readNode(&childNode, &steps);
00638         calculationSteps.clear();
00639         for(unsigned int i = 0; i < steps.size(); i++)
00640         {
00641           switch(steps[i])
00642           {
00643             case NEW_CYCLE: calculationSteps.push_back(NEW_CYCLE);
00644                             break;
00645             case ACHAR:     calculationSteps.push_back(ACHAR);
00646                             break;
00647             case BRABO:     calculationSteps.push_back(BRABO);
00648                             break;
00649             case BUUR:      calculationSteps.push_back(BUUR);
00650                             break;
00651             case CNVRTAFF:  calculationSteps.push_back(CNVRTAFF);
00652                             break;
00653             case DISTOR:    calculationSteps.push_back(DISTOR);
00654                             break;
00655             case FORKON:    calculationSteps.push_back(FORKON);
00656                             break;
00657             case MAFF:      calculationSteps.push_back(MAFF);
00658                             break;
00659             case RELAX:     calculationSteps.push_back(RELAX);
00660                             break;
00661             case STOCK:     calculationSteps.push_back(STOCK);
00662                             break;
00663             case UPDATE:    calculationSteps.push_back(UPDATE);
00664                             break;
00665           }
00666         }
00667       }
00668     }
00669     childNode = childNode.nextSibling();
00670   }
00671 }
00672 
00674 void Calculation::saveCML(QDomElement* root)
00676 {
00677   const QString prefix = "calculation_";
00678   DomUtils::makeNode(root, startVectorFile, prefix + "starting_vector");
00679   DomUtils::makeNode(root, updateBraboInput, prefix + "update_energy_and_forces");
00680   DomUtils::makeNode(root, updateStockInput, prefix + "update_stockholder");
00681   DomUtils::makeNode(root, updateRelaxInput, prefix + "update_geometry_optimization");
00682   DomUtils::makeNode(root, doBasissetCheck, prefix + "check_basissets");
00683   DomUtils::makeNode(root, calcRunning, prefix + "running");
00684   DomUtils::makeNode(root, calcPaused, prefix + "paused");
00685   DomUtils::makeNode(root, currentCycle, prefix + "current_cycle");
00686   DomUtils::makeNode(root, calcError, prefix + "error");
00687   DomUtils::makeNode(root, calcContinuable, prefix + "continuable");
00688   std::vector<unsigned int> calcSteps;
00689   for(std::list<CalculationStep>::iterator it = calculationSteps.begin(); it != calculationSteps.end(); it++)
00690     calcSteps.push_back(static_cast<unsigned int>(*it));
00691   DomUtils::makeNode(root, calcSteps, prefix + "steps");
00692 }
00693 
00695 void Calculation::writeInput()
00699 {
00701   if(!makeDirCurrent(calcDir, tr("Write all input files")))
00702     return;
00703 
00705   QFile fileInp(calcName + ".inp");
00706   if(!fileInp.open(IO_WriteOnly))
00707   {
00708     QMessageBox::warning(parentWidget, tr("Write all input files"), tr("Unable to write the file") +
00709       "\n" + fileInp.name());
00710     return;
00711   }
00712   QTextStream streamInp(&fileInp);
00713   streamInp << QString(braboInput.join("\n")+"\n");
00714   fileInp.close();
00715   if(calcRunning)
00716     return; // when a calculation is running, all other files are already present
00717 
00719   if(CrdFactory::writeToFile(atoms, calcName + ".crd", calcXF) != CrdFactory::OK)
00720   {
00721     QMessageBox::warning(parentWidget, tr("Write all input files"), tr("Unable to write the file") + "\n" + calcName + ".crd");
00722     return;
00723   }
00724 
00726   if(!copyStartVector())
00727     return;
00728 
00730   if(!stockInput.isEmpty())
00731   {
00732     QFile file(calcName + ".stin");
00733     if(!file.open(IO_WriteOnly))
00734     {
00735       QMessageBox::warning(parentWidget, tr("Write all input files"), tr("Unable to write the file") +
00736       "\n" + file.name());
00737       return;
00738     }
00739     QTextStream stream(&file);
00740     stream << QString(stockInput.join("\n")+"\n");
00741     fileInp.close();
00742   }
00743 
00745   if(!maffInput.isEmpty())
00746   {
00747     QFile file(calcName + ".maffinp");
00748     if(!file.open(IO_WriteOnly))
00749     {
00750       QMessageBox::warning(parentWidget, tr("Write all input files"), tr("Unable to write the file") +
00751       "\n" + file.name());
00752       return;
00753     }
00754     QTextStream stream(&file);
00755     stream << QString(maffInput.join("\n")+"\n");
00756     fileInp.close();
00757   }
00758 
00760   if(!relaxInput.isEmpty())
00761   {
00762     QString extension = ".aff";
00763     if(!maffInput.isEmpty())
00764       extension += "1";
00765     QFile file(calcName + extension);
00766     if(!file.open(IO_WriteOnly))
00767     {
00768       QMessageBox::warning(parentWidget, tr("Write all input files"), tr("Unable to write the file") +
00769       "\n" + file.name());
00770       return;
00771     }
00772     QTextStream stream(&file);
00773     stream << QString(relaxInput.join("\n")+"\n");
00774     fileInp.close();
00775   }
00776 }
00777 
00779 void Calculation::clean()
00781 {
00782   if(calcRunning)
00783     return;
00784 
00785   QDir dir(calcDir);
00786   if(!dir.exists())
00787     return; // certainly clean
00788 
00790   if(!makeDirCurrent(calcDir, tr("Clean calculation")))
00791     return;
00792 
00794   QStringList files = dir.entryList(calcName + ".*"); // all in and output files
00795   files += dir.entryList(calcName + "_*"); // all saved outputs
00796   files += dir.entryList("fort.*"); // all fortran unnnamed unit files
00797   QFile file;
00799   for(QStringList::Iterator it = files.begin(); it != files.end(); it++)
00800   {
00801     file.setName(*it);
00802     file.remove();
00803   }
00805   dir.setPath(calcDir + QDir::separator() + "tmp");
00806   if(!dir.exists())
00807     return;
00808   dir.setCurrent(dir.path());
00809   files = dir.entryList(calcName + ".*"); // all in and output files
00810   files += dir.entryList("fort.*"); // all fortran unnnamed unit files
00811   for(QStringList::Iterator it = files.begin(); it != files.end(); it++)
00812   {
00813     file.setName(*it);
00814     file.remove();
00815   }  
00816   dir.cdUp();
00817   dir.rmdir(calcDir + QDir::separator() + "tmp"); // will only be removed if it is empty 
00818 }
00819 
00823 
00825 void Calculation::finishBrabo()
00827 {
00828   assert(calcProcess != 0);
00829 
00830   if(!calcRunning)
00831     return;
00832 
00833   if(calcProcess->isRunning())
00834   {
00835     calcProcess->tryTerminate();
00836     QTimer::singleShot(1000, this, SLOT(finishBrabo));
00837     return;
00838   }
00839   
00841   bool noError = calcProcess->normalExit();
00842   delete calcProcess;
00843   calcProcess = 0;
00844 
00846   if(!noError)
00847   {
00848     if(calculationType == GlobalBase::SinglePointEnergy)
00849       QMessageBox::warning(parentWidget, tr("Energy"), tr("A problem occured during the calculation of the energy"));
00850     else
00851       QMessageBox::warning(parentWidget, tr("Energy & Forces"), tr("A problem occured during the calculation of the energy & forces"));    
00852     calcRunning = false;
00853     if(calcError == NoError)
00854       calcError = UndefinedError;
00855   }
00856   
00858   doNextStep();
00859 }
00860 
00862 void Calculation::readStdOutBrabo()
00864 {
00865   assert(calcProcess != 0);
00866 
00867   if(!calcRunning)
00868     return;
00869   
00870   while(calcProcess->canReadLineStdout())
00871   {
00872     QString line = calcProcess->readLineStdout();
00873     //qDebug("stdout: " + line);
00874     if(line.length() == 75 && line.left(30) != "                              ")
00875     {
00876       bool oki, oke;
00877       unsigned int iteration = line.left(4).toUInt(&oki);
00878       double energy = line.mid(4,16).toDouble(&oke);
00879       if(oki && oke)
00880         emit newIteration(iteration, energy);
00881       if(oki && oke && startVectorFile.isEmpty())
00882         startVectorFile = calcDir + QDir::separator() + calcName + ".sta"; // makes sure this variable is filled as soon as the actual file exists
00883     }
00884     if(calcError == NoError && line.left(58) == "                                        NO CONVERGENCE !!!")
00885       calcError = NoConvergence; // the only error that can be deducted from stdout
00886   }
00887   
00888 /*      // keep the first error that is encountered
00889       if(line == "        ERROR DETECTED        ERROR DETECTED        ERROR DETECTED        ERROR DETECTED        ERROR DETECTED")
00890         calcError = UndefinedError;
00891       else if(line.left(7) == " NUCLEI" && line.mid(17,10) == "TOO CLOSE,")
00892         calcError = CloseNuclei;
00893       qDebug("left7 = |" + line.left(7) + "|, mid = |" + line.mid(17,10) + "|");
00894 */
00895 }
00896 
00898 void Calculation::finishStock()
00900 {
00901   assert(calcProcess != 0);
00902 
00903   if(!calcRunning)
00904     return;
00905 
00906   if(calcProcess->isRunning())
00907   {
00908     calcProcess->tryTerminate();
00909     QTimer::singleShot(1000, this, SLOT(finishStock));
00910     return;
00911   }
00912   
00914   bool noError = calcProcess->normalExit();
00915   delete calcProcess;
00916   calcProcess = 0;
00917 
00919   if(!noError)
00920   {
00921     QMessageBox::warning(parentWidget, tr("Calculation of stockholder charges"), tr("A problem occured during the calculation of the stockholder charges"));    
00922     calcRunning = false;
00923     if(calcError == NoError)
00924       calcError = UndefinedError;
00925     doNextStep();
00926     return;
00927   }
00928 
00930   QFile inputFile(calcDir + QDir::separator() + "fort.7");
00931   QFile appendFile(calcDir + QDir::separator() + calcName + ".pun");
00932   if(!inputFile.open(IO_ReadOnly) || !appendFile.open(IO_WriteOnly | IO_Append))
00933   {
00934     QMessageBox::warning(parentWidget, tr("Calculation of stockholder charges"), tr("A problem occured during the calculation of the stockholder charges"));    
00935     calcRunning = false;
00936     if(calcError == NoError)
00937       calcError = UndefinedError;
00938     doNextStep();
00939     return;
00940   }
00941   appendFile.writeBlock(inputFile.readAll());
00942   inputFile.close();
00943   appendFile.close();
00944 
00945   doNextStep();
00946 }
00947 
00949 void Calculation::finishMAFF()
00951 {
00952   assert(calcProcess != 0);
00953 
00954   if(!calcRunning)
00955     return;
00956 
00957   if(calcProcess->isRunning())
00958   {
00959     calcProcess->tryTerminate();
00960     QTimer::singleShot(1000, this, SLOT(finishMAFF));
00961     return;
00962   }
00963   
00965   bool noError = calcProcess->normalExit();
00966   delete calcProcess;
00967   calcProcess = 0;
00968 
00970   if(!noError)
00971   {
00972     QMessageBox::warning(parentWidget, tr("Updating the internal coordinates"), tr("A problem occured during the generation of new internal coordinates"));    
00973     calcRunning = false;
00974     if(calcError == NoError)
00975       calcError = UndefinedError;
00976   }
00977 
00979   doNextStep();
00980 }
00981 
00983 void Calculation::finishCnvrtAFF()
00985 {
00986   assert(calcProcess != 0);
00987 
00988   if(!calcRunning)
00989     return;
00990 
00991   if(calcProcess->isRunning())
00992   {
00993     calcProcess->tryTerminate();
00994     QTimer::singleShot(1000, this, SLOT(finishCnvrtAFF));
00995     return;
00996   }
00997   
00999   bool noError = calcProcess->normalExit();
01000   delete calcProcess;
01001   calcProcess = 0;
01002 
01004   if(!noError)
01005   {
01006     QMessageBox::warning(parentWidget, tr("Updating the internal coordinates"), tr("A problem occured during the conversion of the new internal coordinates"));    
01007     calcRunning = false;
01008     if(calcError == NoError)
01009       calcError = UndefinedError;
01010     doNextStep();
01011     return;
01012   }
01013 
01015   QFile fileNewAFF(calcDir + QDir::separator() + calcName + ".aff_new");
01016   QFile fileAFF(calcDir + QDir::separator() + calcName + ".aff");
01017   if(!fileNewAFF.open(IO_ReadOnly) || !fileAFF.open(IO_WriteOnly | IO_Translate)) // suddenly Relax wants files with crlf on Windows?
01018   {
01019     QMessageBox::warning(parentWidget, tr("Updating the internal coordinates"), tr("A problem occured during combining the new internal coordinates"));    
01020     calcRunning = false;
01021     if(calcError == NoError)
01022       calcError = UndefinedError;
01023     doNextStep();
01024     return;
01025   }
01026   QTextStream streamNewAFF(&fileNewAFF);
01027   QTextStream streamAFF(&fileAFF);
01029   streamAFF << QString(relaxInput.join("\n")+"\n");
01031   QString line;
01032   while(!line.contains("GBMA", false) && !line.contains("BMAT", false))
01033     line = streamNewAFF.readLine();
01034   streamAFF << streamNewAFF.read(); // add the remainder of the file
01035   fileNewAFF.close();
01036   fileAFF.close();
01037 
01039   doNextStep();
01040 }
01041 
01043 void Calculation::finishRelax()
01046 {
01047   assert(calcProcess != 0);
01048 
01049   if(!calcRunning)
01050     return;
01051 
01052   if(calcProcess->isRunning())
01053   {
01054     calcProcess->tryTerminate();
01055     QTimer::singleShot(1000, this, SLOT(finishRelax));
01056     return;
01057   }
01058   
01060   bool noError = calcProcess->normalExit();
01061   delete calcProcess;
01062   calcProcess = 0;
01063 
01064   qDebug("finishRelax: noError = %d", noError);
01066   if(!noError)
01067   {
01068     QMessageBox::warning(parentWidget, tr("Geometry optimization"), tr("A problem occured during the calculation of new coordinates"));    
01069     calcRunning = false;
01070     if(calcError == NoError)
01071       calcError = UndefinedError;
01072     doNextStep();
01073     return;
01074   }
01075 
01077   QFile fileC00(calcDir + QDir::separator() + calcName + ".c00");
01078   if(fileC00.exists())
01079   {
01080     // read the coordinates
01081     unsigned int result = CrdFactory::readFromFile(atoms, fileC00.name());
01082     if(result != CrdFactory::OK)
01083     {
01084       QMessageBox::warning(parentWidget, tr("Run calculation"), tr("A problem occured reading the optimized coordinates."));
01085       if(calcError == NoError)
01086         calcError = UndefinedError;
01087     }
01088     else
01089       calcError = NoError;
01090     calcRunning = false;
01091     doNextStep();
01092     return;
01093   }
01094 
01096   QFile fileNCR(calcDir + QDir::separator() + calcName + ".ncr");
01097   if(!fileNCR.exists())
01098   {
01099     QMessageBox::warning(parentWidget, tr("Run calculation"), tr("A problem occured reading the new coordinates\n(the coordinate file does not exist)."));
01100     calcRunning = false;
01101     if(calcError == NoError)
01102       calcError = UndefinedError;
01103     doNextStep();
01104     return;
01105   }
01106 
01108   QFile fileCrd(calcDir + QDir::separator() + calcName + ".crd");
01109   if(!fileCrd.remove()) // this is suddenly needed otherwise the rename won't work on Windows
01110   {
01111     QMessageBox::warning(parentWidget, tr("Run calculation"), tr("A problem occured updating the coordinates."));
01112     calcRunning  = false;
01113     if(calcError == NoError)
01114       calcError = UndefinedError;
01115     doNextStep();
01116     return;
01117   }
01118   QUrlOperator local(calcDir);
01119   const QNetworkOperation* operation = local.rename(calcName + ".ncr", calcName + ".crd");
01120   while((operation->state() == QNetworkProtocol::StWaiting) || (operation->state() == QNetworkProtocol::StInProgress))
01121     qApp->processEvents(); // shouldn't do much as renaming should be very fast as opposed to copying
01122   if(operation->state() != QNetworkProtocol::StDone)
01123   {
01124     qDebug("operation->state() = %d",operation->state());
01125     qDebug(" error code = %d",operation->errorCode());
01126     qDebug("error string = "+operation->protocolDetail());
01127     QMessageBox::warning(parentWidget, tr("Run calculation"), tr("A problem occured updating the coordinates."));
01128     calcRunning = false;
01129     if(calcError == NoError)
01130       calcError = UndefinedError;
01131   }
01132 
01133   doNextStep();
01134 }
01135 
01137 void Calculation::readStdOutAll()
01139 {
01140   assert(calcProcess != 0);
01141 
01142   if(!calcRunning)
01143     return;
01144   
01145   while(calcProcess->canReadLineStdout())
01146     calcProcess->readLineStdout();
01147 }
01148 
01152 
01154 bool Calculation::checkBasissets()
01156 {
01158   QStringList missingFiles;
01159   for(QStringList::iterator it = basissetList.begin(); it != basissetList.end(); it++)
01160   {
01161     QFile file(*it);
01162     if(!file.exists())
01163       missingFiles += *it;
01164   }
01166   if(missingFiles.isEmpty())
01167   {
01168     doBasissetCheck = false;
01169     return true;
01170   }
01171   
01173   QMessageBox::warning(parentWidget, tr("Check basis sets") , tr("The following basis set files could not be found:") 
01174                        + "\n\n - " + missingFiles.join("\n - "));
01175   return false;
01176 }
01177 
01179 bool Calculation::checkExecutables()
01181 {
01183   QStringList missingExecutables;
01184   QFile file(Paths::brabo);
01185   if(!file.exists())
01186     missingExecutables += "Brabo (" + Paths::brabo  +")";
01187   if(!stockInput.isEmpty())
01188   {
01189     file.setName(Paths::relax);
01190     if(!file.exists())
01191       missingExecutables += "Stock (" + Paths::stock  +")";
01192   }
01193   if(calculationType == GlobalBase::GeometryOptimization)
01194   {
01195     file.setName(Paths::relax);
01196     if(!file.exists())
01197       missingExecutables += "Relax (" + Paths::relax  +")";
01198     if(!maffInput.isEmpty())
01199     {
01200       file.setName(Paths::maff);
01201       if(!file.exists())
01202         missingExecutables += "Maff (" + Paths::maff  +")";
01203       file.setName(Paths::cnvrtaff);
01204       if(!file.exists())
01205         missingExecutables += "Cnvrtaff (" + Paths::cnvrtaff +")";
01206     }
01207   }
01209   if(missingExecutables.isEmpty())
01210     return true;
01211 
01213   QMessageBox::warning(parentWidget, tr("Check executables") , tr("The following executable files could not be found:") 
01214                        + "\n\n - " + missingExecutables.join("\n - ") + "\n\n" + tr("Please check the Preferences."));
01215   return false;
01216 }
01217 
01219 bool Calculation::makeDirCurrent(const QString dir, const QString title)
01222 {
01223   QDir workDir = dir;
01224   if(!workDir.exists())
01225   {
01226     if(!workDir.mkdir(workDir.path()))
01227     {
01228       QMessageBox::warning(parentWidget, title, tr("Unable to create the directory ") + workDir.path());
01229       return false;
01230     }
01231   }
01232   if(!QDir::setCurrent(workDir.path()))
01233   {
01234     QMessageBox::warning(parentWidget, title, tr("Unable to change to the directory ") + workDir.path());
01235     return false;
01236   }
01237   return true;
01238 }
01239 
01241 bool Calculation::copyStartVector()
01243 {
01245   if(startVectorFile.isEmpty())
01246     return true;
01247 
01249   if(startVectorFile == calcDir + QDir::separator() + calcName + ".sta")
01250     return true;
01251 
01253   qDebug("copying startvector");
01254   if(!copyFile(startVectorFile, calcDir + QDir::separator() + calcName + ".sta"))
01255   {
01256     QMessageBox::warning(parentWidget, tr("Copy starting vector"), tr("Unable to copy the starting vector \n") 
01257                          + startVectorFile + tr(" to the calculation directory"));
01258     return false;
01259   }
01260   return true;
01261 }
01262 
01264 void Calculation::doNextStep()
01267 {
01268   qDebug("doNextStep: calcPaused = %d, calcRunning = %d, stopRequested = %d",
01269                       calcPaused, calcRunning, stopRequested);
01270 
01271   // do nothing if the calculation is paused
01272   if(calcPaused)
01273     return;
01274 
01275   setModified();
01276 
01277   // check whether the calculation has finished successfully or an error occured
01278   if(!calcRunning || stopRequested)
01279   {
01280     runCleanup();
01281     return;
01282   }
01283 
01284   // get the current step
01285   CalculationStep currentStep = calculationSteps.front();
01286   // take it from the front and insert it at the back for the next call of doNextStep
01287   calculationSteps.pop_front();
01288   calculationSteps.push_back(currentStep);
01289 
01290   // do the appropriate action 
01291   const unsigned int thisStep = currentStep;
01292   switch(thisStep) // switch doesn't work with enums
01293   {
01294     case NEW_CYCLE: // start of a new cycle
01295                     qDebug("doNextStep: currentStep = NEW_CYCLE");
01296                     if(calculationType == GlobalBase::SinglePointEnergy || calculationType == GlobalBase::EnergyAndForces)
01297                       calcRunning = false;
01298                     else if(currentCycle == calcMaxCycle)
01299                     {
01300                       calcRunning = false;
01301                       if(calcError == NoError)
01302                         calcError = MaxCyclesExceeded;
01303                     }
01304                     else
01305                     {
01306                       // backup the output files
01307                       backupOutputs();
01308                       // start a new optimization cycle
01309                       currentCycle++;
01310                       emit newCycle(currentCycle+1);
01311                       doNextStep();
01312                       return;
01313                     }
01314                     break;
01315 
01316     case BRABO:     // run BRABO     
01317                     qDebug("doNextStep: currentStep = BRABO");
01318                     runBrabo();
01319                     break;
01320 
01321     case CNVRTAFF:  // run CNVRTAFF
01322                     qDebug("doNextStep: currentStep = CNVRTAFF");
01323                     if(!maffInput.isEmpty() && ((affUpdateFreq == 0 && currentCycle == 0) || (affUpdateFreq != 0 && (currentCycle % affUpdateFreq == 0) || updateRelaxInput)))
01324                       // only run CnvrtAFF/MAFF if
01325                       // - there is an input file for maff (if not, no automatic generation of IC's is requested
01326                       // - it's the first cyle and only 1 AFF file is to be made (when affUpdateFreq == 0)
01327                       // - the AFF file should be regenerated every affUpdateFreq cycles
01328                       // - automatic regeneration and a change in the AFF header file
01329                       runCnvrtAFF();
01330                     else
01331                     {
01332                       doNextStep();
01333                       return;
01334                     }
01335                     break;
01336 
01337     case MAFF:      // run MAFF
01338                     qDebug("doNextStep: currentStep = MAFF");
01339                     if(!maffInput.isEmpty() && ((affUpdateFreq == 0 && currentCycle == 0) || (affUpdateFreq != 0 && (currentCycle % affUpdateFreq == 0) || updateRelaxInput)))
01340                       // only run CnvrtAFF/MAFF if
01341                       // - there is an input file for maff (if not, no automatic generation of IC's is requested
01342                       // - it's the first cyle and only 1 AFF file is to be made (when affUpdateFreq == 0)
01343                       // - the AFF file should be regenerated every affUpdateFreq cycles
01344                       // - automatic generation and a change in the AFF header file
01345                       runMAFF();
01346                     else
01347                     {
01348                       doNextStep();
01349                       return;
01350                     }
01351                     break;
01352 
01353     case RELAX:     // run RELAX
01354                     qDebug("doNextStep: currentStep = RELAX");
01355                     runRelax();
01356                     break;
01357          
01358     case STOCK:     // run STOCK
01359                     qDebug("doNextStep: currentStep = STOCK");
01360                     if(stockInput.isEmpty())
01361                     {
01362                       doNextStep();
01363                       return;
01364                     }
01365                     else
01366                       runStock(); // only run it when these charges are requested
01367                     break;
01368 
01369     case UPDATE:    // run UPDATE
01370                     qDebug("doNextStep: currentStep = UPDATE");
01371                     runUpdate();
01372                     return; // never call runCleanup after runUpdate (runCleanup never changes calcRunning)
01373                     break;
01374   }
01375   // do a cleanup if something went wrong or the end of the calculation, 
01376   // signalled by setting calcRunning to false
01377   if(!calcRunning)
01378     runCleanup();
01379 }
01380 
01382 void Calculation::runBrabo()
01385 {
01386   assert(calcProcess == 0);
01387 
01388   if(updateBraboInput)
01389   {
01390     // update this input if it should exist as a physical file on disk
01391 
01392     updateBraboInput = false;
01393   }
01394 
01397   QString stdInput;
01398   if(startVectorFile.isEmpty())
01399   {
01400     for(QStringList::Iterator it = braboInput.begin(); it != braboInput.end(); it++)
01401     {
01402       if((*it).left(4) != "star")
01403         stdInput += *it + "\n";
01404     }
01405   }
01406   else
01407     stdInput = braboInput.join("\n")+"\n";
01408 
01411   if(!copyStartVector())
01412   {
01413     calcRunning = false;
01414     if(calcError == NoError)
01415       calcError = UndefinedError;
01416     doNextStep();
01417     return;
01418   }
01419 
01421   calcProcess = new QProcess(this);
01422   calcProcess->setWorkingDirectory(calcDir);
01423   calcProcess->addArgument(Paths::brabo);
01424   connect(calcProcess, SIGNAL(processExited()), this, SLOT(finishBrabo()));
01425   connect(calcProcess, SIGNAL(readyReadStdout()), this, SLOT(readStdOutBrabo()));
01426   calcProcess->launch(stdInput);
01427 }
01428 
01430 void Calculation::runStock()
01432 {
01433   assert(calcProcess == 0);
01434 
01435   if(updateStockInput)
01436   {
01438     QFile file(calcDir + QDir::separator() + calcName + ".stin");
01439     if(!file.open(IO_WriteOnly))
01440     {
01441       QMessageBox::warning(parentWidget, tr("Start the calculation of stockholder charges"), tr("Unable to update the file") +
01442         "\n" + file.name());
01443       calcRunning = false;
01444       if(calcError == NoError)
01445         calcError = UndefinedError;
01446       doNextStep();
01447       return;
01448     }
01449     QTextStream stream(&file);
01450     stream << QString(stockInput.join("\n")+"\n");
01451     file.close();
01452 
01454     if(!atdensFile.isEmpty())
01455     {
01456       file.setName(calcDir + QDir::separator() + calcName + ".atdens");
01457       if(!file.open(IO_WriteOnly | IO_Translate))
01458       {
01459         QMessageBox::warning(parentWidget, tr("Start the calculation of stockholder charges"), tr("Unable to update the file") +
01460           "\n" + file.name());
01461         calcRunning = false;
01462         if(calcError == NoError)
01463           calcError = UndefinedError;
01464         doNextStep();
01465         return;
01466       }
01467       stream.setDevice(&file);
01468       stream << atdensFile;
01469       file.close();
01470       atdensFile = QString::null;
01471     }
01472     updateStockInput = false;
01473   }
01474 
01475   calcProcess = new QProcess(this);
01476   calcProcess->setWorkingDirectory(calcDir);
01477   calcProcess->addArgument(Paths::stock);
01478   connect(calcProcess, SIGNAL(processExited()), this, SLOT(finishStock()));
01479   connect(calcProcess, SIGNAL(readyReadStdout()), this, SLOT(readStdOutAll()));
01480   calcProcess->launch(calcName + "\n");
01481 }
01482 
01484 void Calculation::runMAFF()
01486 {
01487   assert(calcProcess == 0);
01488   assert(!maffInput.isEmpty());
01489 
01490   calcProcess = new QProcess(this);
01491   calcProcess->setWorkingDirectory(calcDir);
01492   calcProcess->addArgument(Paths::maff);
01493   connect(calcProcess, SIGNAL(processExited()), this, SLOT(finishMAFF()));
01494   connect(calcProcess, SIGNAL(readyReadStdout()), this, SLOT(readStdOutAll()));
01495   calcProcess->launch(maffInput.join("\n")+"\n"); 
01496 }
01497 
01499 void Calculation::runCnvrtAFF()
01501 {
01502   assert(calcProcess == 0);
01503 
01504   updateRelaxInput = false; // should be disabled here because if in runMAFF this 
01505                             // routine wouldn't be called and if not at all
01506                             // an update in runRelax would overwrite stuff.
01507 
01508   calcProcess = new QProcess(this);
01509   calcProcess->setWorkingDirectory(calcDir);
01510   calcProcess->addArgument(Paths::cnvrtaff);
01511   connect(calcProcess, SIGNAL(processExited()), this, SLOT(finishCnvrtAFF()));
01512   connect(calcProcess, SIGNAL(readyReadStdout()), this, SLOT(readStdOutAll()));
01513   calcProcess->launch(calcName + "\n");
01514 }
01515 
01517 void Calculation::runRelax()
01519 {
01520   assert(calcProcess == 0);
01521 
01522   if(updateRelaxInput)
01523   {
01525     QFile file(calcDir + QDir::separator() + calcName + ".aff");
01526     if(!file.open(IO_WriteOnly))
01527     {
01528       QMessageBox::warning(parentWidget, tr("Updating the internal coordinates"), tr("A problem occured writing the new internal coordinates"));    
01529       calcRunning = false;
01530       if(calcError == NoError)
01531         calcError = UndefinedError;
01532       doNextStep();
01533       return;
01534     }
01535     QTextStream stream(&file);
01536     stream << QString(relaxInput.join("\n") + "\n");
01537     file.close();    
01538     updateRelaxInput = false;
01539   }
01540 
01541   calcProcess = new QProcess(this);
01542   calcProcess->setWorkingDirectory(calcDir);
01543   calcProcess->addArgument(Paths::relax);
01544   connect(calcProcess, SIGNAL(processExited()), this, SLOT(finishRelax()));
01545   connect(calcProcess, SIGNAL(readyReadStdout()), this, SLOT(readStdOutAll()));
01546   calcProcess->launch(calcName + "\n" + QString::number(currentCycle+1) + "\nn\n" + QString::number(scaleFactor(currentCycle)) +"\n");
01547 }
01548 
01550 void Calculation::runCleanup()
01552 {
01553   qDebug("Calculation::runCleanup() called");
01554 
01555   if(calcError == NoError)
01556     setContinuable(false); // when the structure is optimized, it should never be continued
01557 
01558   emit finished(calcError);
01559 }
01560 
01562 void Calculation::runUpdate()
01566 {
01568   if(calculationType == GlobalBase::GeometryOptimization && currentCycle != 0)
01569   {
01571     QFile file(calcDir + QDir::separator() + calcName + ".crd");
01572     if(!file.exists() || CrdFactory::readFromFile(atoms, file.name()) != CrdFactory::OK)
01573       QMessageBox::warning(parentWidget, tr("Run calculation"), tr("The view could not be updated with the new coordinates."));
01574   }
01577 
01579   if(calculationType != GlobalBase::SinglePointEnergy)
01580   {
01582     QFile file(calcDir + QDir::separator() + calcName + ".pun");    
01583     if(!file.exists() || CrdFactory::readForces(atoms, file.name()) != CrdFactory::OK)
01584     {
01585       QMessageBox::warning(parentWidget, tr("Run calculation"), tr("The view could not be updated with the new forces."));
01586       qDebug("filename: "+file.name());
01587       qDebug("return value: %d", CrdFactory::readForces(atoms, file.name())); 
01588     }
01589   }
01590 
01592   atoms->setCharges(loadFromPunch("MULL", atoms->count(), 10, 8), AtomSet::Mulliken);
01593 
01595   atoms->setCharges(loadFromPunch("STOC", atoms->count(), 10, 8), AtomSet::Stockholder);
01596 
01597   emit updated();
01598   doNextStep();
01599 }
01600 
01602 double Calculation::scaleFactor(const unsigned int step)
01604 {
01605   double result;
01606   unsigned int iterStep = 0;
01607   result = scaleFactors[0];
01608   for(unsigned int i = 0; i < scaleSteps.size(); i++)
01609   {
01610     iterStep += scaleSteps[i];
01611     if(step <= iterStep)
01612       result = scaleFactors[i];
01613     else
01614       break;
01615   }
01616   qDebug("Calculation::scaleFactor returns %f", result);
01617   for(unsigned int i = 0; i < scaleSteps.size(); i++)
01618     qDebug(" %d: step %d with factor %f",i,scaleSteps[i],scaleFactors[i]);
01619 
01620   return result;
01621 }
01622 
01624 void Calculation::backupOutputs()
01627 {
01628   if(backupFrequency == 0 || currentCycle % backupFrequency != 0)
01629     return;
01630 
01631   if(backupBrabo)
01632     copyFile(calcDir + QDir::separator() + calcName + ".out", 
01633              calcDir + QDir::separator() + calcName + "_" + QString::number(currentCycle+1) + ".out");
01634   if(backupStock && !stockInput.isEmpty())
01635     copyFile(calcDir + QDir::separator() + calcName + ".stou", 
01636              calcDir + QDir::separator() + calcName + "_" + QString::number(currentCycle+1) + ".stou");
01637   if(backupRelax && calculationType == GlobalBase::GeometryOptimization)
01638     copyFile(calcDir + QDir::separator() + calcName + ".aou", 
01639              calcDir + QDir::separator() + calcName + "_" + QString::number(currentCycle+1) + ".aou");
01640   if(backupAFF && calculationType == GlobalBase::GeometryOptimization)
01641     copyFile(calcDir + QDir::separator() + calcName + ".aff", 
01642              calcDir + QDir::separator() + calcName + "_" + QString::number(currentCycle+1) + ".aff");
01643   if(backupCRD)
01644     copyFile(calcDir + QDir::separator() + calcName + ".crd", 
01645              calcDir + QDir::separator() + calcName + "_" + QString::number(currentCycle+1) + ".crd");
01646 }
01647 
01649 bool Calculation::copyFile(const QString source, const QString destination)
01653 {
01654   QFile inputFile(source);
01655   QFile outputFile(destination);
01656   if(!inputFile.open(IO_ReadOnly) || !outputFile.open(IO_WriteOnly))
01657     return false;
01658   
01659   outputFile.writeBlock(inputFile.readAll());
01660   inputFile.close();
01661   outputFile.close();
01662   return true;
01663 }
01664 
01666 QStringList Calculation::output(const QString extension, const unsigned int step)
01669 {
01670   QStringList result;
01671   QString fileName;
01672   if(step == 0)
01673     fileName = calcName + extension;
01674   else
01675     fileName = calcName + "_" + QString::number(step) + extension;
01676 
01677   QFile file(calcDir + QDir::separator() + fileName);
01678   if(file.open(IO_ReadOnly))
01679   {
01680     QTextStream stream(&file);
01681     //while(!stream.atEnd())
01682     //  result += stream.readLine();
01683     result = QStringList::split("\n", stream.read(), true);
01684   }
01685   return result;
01686 }
01687 
01689 std::vector<double> Calculation::loadFromPunch(const QString code, const unsigned int numValues, const unsigned int fieldSize, const unsigned int fieldsPerLine)
01695 {
01696   std::vector<double> result;
01697 
01699   QFile file(calcDir + QDir::separator() + calcName + ".pun");
01700   if(!file.open(IO_ReadOnly))
01701     return result; // An empty result indicates failure
01702 
01703   qDebug("reading data from " + file.name());
01704   qDebug("looking for code |****" + code+ "|");
01705 
01707   QTextStream stream(&file);
01708   int codeLength = 4 + code.length();  
01709   while(stream.readLine().left(codeLength) != QString("****" + code) && !stream.atEnd())
01710     ;
01711   
01713   if(stream.atEnd())
01714   {
01715     result.clear();
01716     return result;
01717   }
01718   
01721   QString line;
01722   for(unsigned int i = 0; i < numValues/fieldsPerLine; i++)
01723   {
01724     line = stream.readLine(); // contains fieldsPerLine values
01725     for(unsigned int j = 0; j < 8; j++)
01726       result.push_back(line.mid(j*fieldSize,fieldSize).toDouble());
01727 
01728     if(stream.atEnd())
01729     {
01730       result.clear();
01731       return result;
01732     }
01733   }
01735   line = stream.readLine(); 
01736   for(unsigned int j = 0; j < numValues % fieldsPerLine; j++)
01737     result.push_back(line.mid(j*fieldSize,fieldSize).toDouble());
01738 
01739   assert(result.size() == numValues);
01740   return result;
01741 }
01742 

Generated on Fri May 19 14:31:54 2006 for Brabosphere by  doxygen 1.4.6-NO