00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00019
00045
00046
00047
00049
00050
00051 #include <cassert>
00052 #include <iostream>
00053
00054
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
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
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
00164 calcContinue = QMessageBox::question(parentWidget, tr("Geometry optimization"),
00165 tr("The geometry optimization can possibly be continued."),
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 + "_*");
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
00201
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
00213 calculationSteps.push_back(NEW_CYCLE);
00214
00215 stopRequested = false;
00216 calcRunning = true;
00217 currentCycle = 0;
00218 calcError = NoError;
00219
00220
00221 doNextStep();
00222 return true;
00223 }
00224
00226 bool Calculation::pause()
00231 {
00232
00233 if(!calcRunning)
00234 return false;
00235
00236
00237 if(calcPaused)
00238 return start();
00239
00240
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)
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:
00274 stopRequested = true;
00275 setModified();
00276 break;
00277 case 1:
00278 if(calcProcess != 0)
00279 calcProcess->kill();
00280 calcRunning = false;
00281 if(calcError == NoError)
00282 calcError = ManualStop;
00283 doNextStep();
00284 break;
00285 case 2:
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
00332
00333
00334
00335
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)
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)
00350 startVectorFile = startVector;
00351 else
00352 startVectorFile = QString::null;
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
00370
00371
00372
00373
00374
00375 fi.setFile(startVector);
00376 if(fi.size() == startVectorSize1 || fi.size() == startVectorSize2)
00377 startVectorFile = startVector;
00378 else
00379 startVectorFile = QString::null;
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
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, ¤tCycle);
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;
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;
00788
00790 if(!makeDirCurrent(calcDir, tr("Clean calculation")))
00791 return;
00792
00794 QStringList files = dir.entryList(calcName + ".*");
00795 files += dir.entryList(calcName + "_*");
00796 files += dir.entryList("fort.*");
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 + ".*");
00810 files += dir.entryList("fort.*");
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");
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
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";
00883 }
00884 if(calcError == NoError && line.left(58) == " NO CONVERGENCE !!!")
00885 calcError = NoConvergence;
00886 }
00887
00888
00889
00890
00891
00892
00893
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))
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();
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
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())
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();
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
01272 if(calcPaused)
01273 return;
01274
01275 setModified();
01276
01277
01278 if(!calcRunning || stopRequested)
01279 {
01280 runCleanup();
01281 return;
01282 }
01283
01284
01285 CalculationStep currentStep = calculationSteps.front();
01286
01287 calculationSteps.pop_front();
01288 calculationSteps.push_back(currentStep);
01289
01290
01291 const unsigned int thisStep = currentStep;
01292 switch(thisStep)
01293 {
01294 case 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
01307 backupOutputs();
01308
01309 currentCycle++;
01310 emit newCycle(currentCycle+1);
01311 doNextStep();
01312 return;
01313 }
01314 break;
01315
01316 case BRABO:
01317 qDebug("doNextStep: currentStep = BRABO");
01318 runBrabo();
01319 break;
01320
01321 case CNVRTAFF:
01322 qDebug("doNextStep: currentStep = CNVRTAFF");
01323 if(!maffInput.isEmpty() && ((affUpdateFreq == 0 && currentCycle == 0) || (affUpdateFreq != 0 && (currentCycle % affUpdateFreq == 0) || updateRelaxInput)))
01324
01325
01326
01327
01328
01329 runCnvrtAFF();
01330 else
01331 {
01332 doNextStep();
01333 return;
01334 }
01335 break;
01336
01337 case MAFF:
01338 qDebug("doNextStep: currentStep = MAFF");
01339 if(!maffInput.isEmpty() && ((affUpdateFreq == 0 && currentCycle == 0) || (affUpdateFreq != 0 && (currentCycle % affUpdateFreq == 0) || updateRelaxInput)))
01340
01341
01342
01343
01344
01345 runMAFF();
01346 else
01347 {
01348 doNextStep();
01349 return;
01350 }
01351 break;
01352
01353 case RELAX:
01354 qDebug("doNextStep: currentStep = RELAX");
01355 runRelax();
01356 break;
01357
01358 case STOCK:
01359 qDebug("doNextStep: currentStep = STOCK");
01360 if(stockInput.isEmpty())
01361 {
01362 doNextStep();
01363 return;
01364 }
01365 else
01366 runStock();
01367 break;
01368
01369 case UPDATE:
01370 qDebug("doNextStep: currentStep = UPDATE");
01371 runUpdate();
01372 return;
01373 break;
01374 }
01375
01376
01377 if(!calcRunning)
01378 runCleanup();
01379 }
01380
01382 void Calculation::runBrabo()
01385 {
01386 assert(calcProcess == 0);
01387
01388 if(updateBraboInput)
01389 {
01390
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;
01505
01506
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);
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
01682
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;
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();
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