root/src/xtalopt/ui/tab_edit.cpp @ 364d7157c1b4363ccb37a2c39e7e8579d62163d3

Revision 364d7157c1b4363ccb37a2c39e7e8579d62163d3, 16.3 KB (checked in by David C. Lonie <loniedavid@…>, 13 months ago)

Added interface to MOPAC code.

  • Property mode set to 100644
Line 
1/**********************************************************************
2  XtalOpt - Tools for advanced crystal optimization
3
4  Copyright (C) 2009-2011 by David Lonie
5
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Library General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 ***********************************************************************/
16
17#include <xtalopt/ui/tab_edit.h>
18
19#include <xtalopt/optimizers/castep.h>
20#include <xtalopt/optimizers/gulp.h>
21#include <xtalopt/optimizers/mopac.h>
22#include <xtalopt/optimizers/pwscf.h>
23#include <xtalopt/optimizers/vasp.h>
24#include <xtalopt/ui/dialog.h>
25#include <xtalopt/xtalopt.h>
26
27#include <globalsearch/macros.h>
28#include <globalsearch/queueinterfaces/loadleveler.h>
29#include <globalsearch/queueinterfaces/local.h>
30#include <globalsearch/queueinterfaces/lsf.h>
31#include <globalsearch/queueinterfaces/pbs.h>
32#include <globalsearch/queueinterfaces/sge.h>
33#include <globalsearch/queueinterfaces/slurm.h>
34
35#include <QtCore/QSettings>
36
37#include <QtGui/QComboBox>
38#include <QtGui/QFont>
39#include <QtGui/QFileDialog>
40#include <QtGui/QListWidgetItem>
41#include <QtGui/QTextEdit>
42
43using namespace GlobalSearch;
44
45namespace XtalOpt {
46
47  TabEdit::TabEdit( XtalOptDialog *parent, XtalOpt *p ) :
48    DefaultEditTab(parent, p)
49  {
50    // Fill m_optimizers in order of XtalOpt::OptTypes
51    m_optimizers.clear();
52    const unsigned int numOptimizers = 5;
53    for (unsigned int i = 0; i < numOptimizers; ++i) {
54      switch (i) {
55      case XtalOpt::OT_VASP:
56        m_optimizers.append(new VASPOptimizer (m_opt));
57        break;
58      case XtalOpt::OT_GULP:
59        m_optimizers.append(new GULPOptimizer (m_opt));
60        break;
61      case XtalOpt::OT_PWscf:
62        m_optimizers.append(new PWscfOptimizer (m_opt));
63        break;
64      case XtalOpt::OT_CASTEP:
65        m_optimizers.append(new CASTEPOptimizer (m_opt));
66        break;
67      case XtalOpt::OT_MOPAC:
68        m_optimizers.append(new MopacOptimizer (m_opt));
69        break;
70      }
71    }
72
73    // Fill m_optimizers in order of XtalOpt::QueueInterfaces
74    m_queueInterfaces.clear();
75    const unsigned int numQIs = 6;
76    for (unsigned int i = 0; i < numQIs; ++i) {
77      switch (i) {
78      case XtalOpt::QI_LOCAL:
79        m_queueInterfaces.append(new LocalQueueInterface (m_opt));
80        break;
81#ifdef ENABLE_SSH
82      case XtalOpt::QI_PBS:
83        m_queueInterfaces.append(new PbsQueueInterface (m_opt));
84        break;
85      case XtalOpt::QI_SGE:
86        m_queueInterfaces.append(new SgeQueueInterface (m_opt));
87        break;
88      case XtalOpt::QI_SLURM:
89        m_queueInterfaces.append(new SlurmQueueInterface (m_opt));
90        break;
91      case XtalOpt::QI_LSF:
92        m_queueInterfaces.append(new LsfQueueInterface (m_opt));
93        break;
94      case XtalOpt::QI_LOADLEVELER:
95        m_queueInterfaces.append(new LoadLevelerQueueInterface (m_opt));
96        break;
97        //
98        // Don't forget to modify numQIs above, or additions here won't matter!
99        //
100#endif // ENABLE_SSH
101      }
102    }
103
104    connect(ui_list_edit, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
105            this, SLOT(changePOTCAR(QListWidgetItem*)));
106
107    DefaultEditTab::initialize();
108
109    populateTemplates();
110  }
111
112  TabEdit::~TabEdit()
113  {
114  }
115
116  void TabEdit::writeSettings(const QString &filename) {
117    SETTINGS(filename);
118
119    settings->beginGroup("xtalopt/edit");
120    const int VERSION = 2;
121    settings->setValue("version",          VERSION);
122
123    settings->setValue("description", m_opt->description);
124    settings->setValue("localpath", m_opt->filePath);
125    settings->setValue("remote/host", m_opt->host);
126    settings->setValue("remote/port", m_opt->port);
127    settings->setValue("remote/username", m_opt->username);
128    settings->setValue("remote/rempath", m_opt->rempath);
129
130    settings->setValue("optimizer", m_opt->optimizer()->getIDString().toLower());
131    settings->setValue("queueInterface", m_opt->queueInterface()->getIDString().toLower());
132
133    settings->endGroup();
134    m_opt->optimizer()->writeSettings(filename);
135
136    DESTROY_SETTINGS(filename);
137  }
138
139  void TabEdit::readSettings(const QString &filename) {
140    SETTINGS(filename);
141
142    XtalOpt *xtalopt = qobject_cast<XtalOpt*>(m_opt);
143
144    settings->beginGroup("xtalopt/edit");
145    int loadedVersion = settings->value("version", 0).toInt();
146
147    m_opt->port = settings->value("remote/port", 22).toInt();
148
149    // Temporary variables to test settings. This prevents empty
150    // scheme values from overwriting defaults.
151    QString tmpstr;
152
153    tmpstr = settings->value("description", "").toString();
154    if (!tmpstr.isEmpty()) {
155      m_opt->description = tmpstr;
156    }
157
158    tmpstr = settings->value("remote/rempath", "").toString();
159    if (!tmpstr.isEmpty()) {
160      m_opt->rempath = tmpstr;
161    }
162
163    tmpstr = settings->value("localpath", "").toString();
164    if (!tmpstr.isEmpty()) {
165      m_opt->filePath = tmpstr;
166    }
167
168    tmpstr = settings->value("remote/host", "").toString();
169    if (!tmpstr.isEmpty()) {
170      m_opt->host = tmpstr;
171    }
172
173    tmpstr = settings->value("remote/username", "").toString();
174    if (!tmpstr.isEmpty()) {
175      m_opt->username = tmpstr;
176    }
177
178    if (loadedVersion >= 2) {
179      QString optimizer =
180        settings->value("optimizer", "gulp").toString().toLower();
181      for (QList<Optimizer*>::const_iterator
182             it = m_optimizers.constBegin(),
183             it_end = m_optimizers.constEnd();
184           it != it_end; ++it) {
185        if ((*it)->getIDString().toLower().compare(optimizer) == 0) {
186          emit optimizerChanged(*it);
187          break;
188        }
189      }
190
191      QString queueInterface =
192        settings->value("queueInterface", "local").toString().toLower();
193      for (QList<QueueInterface*>::const_iterator
194             it = m_queueInterfaces.constBegin(),
195             it_end = m_queueInterfaces.constEnd();
196           it != it_end; ++it) {
197        if ((*it)->getIDString().toLower().compare(queueInterface) == 0) {
198          emit queueInterfaceChanged(*it);
199          break;
200        }
201      }
202    }
203
204    settings->endGroup();
205
206    // Update config data
207    switch (loadedVersion) {
208    case 0:
209    case 1: // Renamed optType to optimizer, added
210            // queueInterface. Both now use lowercase strings to
211            // identify. Took ownership of variables previously held
212            // by tabsys.
213      {
214#ifdef ENABLE_SSH
215        // Extract optimizer ID
216        ui_combo_optimizers->setCurrentIndex
217          (settings->value("xtalopt/edit/optType", 0).toInt());
218        // Set QueueInterface based on optimizer
219        switch (ui_combo_optimizers->currentIndex()) {
220        case XtalOpt::OT_VASP:
221          ui_combo_queueInterfaces->setCurrentIndex(XtalOpt::QI_PBS);
222          // Copy over job.pbs
223          settings->setValue
224            ("xtalopt/optimizer/VASP/QI/PBS/job.pbs_list",
225             settings->value
226             ("xtalopt/optimizer/VASP/job.pbs_list", QStringList("")));
227          break;
228        case XtalOpt::OT_PWscf:
229          ui_combo_queueInterfaces->setCurrentIndex(XtalOpt::QI_PBS);
230          // Copy over job.pbs
231          settings->setValue
232            ("xtalopt/optimizer/PWscf/QI/PBS/job.pbs_list",
233             settings->value
234             ("xtalopt/optimizer/PWscf/job.pbs_list", QStringList("")));
235          break;
236        case XtalOpt::OT_CASTEP:
237          ui_combo_queueInterfaces->setCurrentIndex(XtalOpt::QI_PBS);
238          // Copy over job.pbs
239          settings->setValue
240            ("xtalopt/optimizer/CASTEP/QI/PBS/job.pbs_list",
241             settings->value
242             ("xtalopt/optimizer/CASTEP/job.pbs_list", QStringList("")));
243          break;
244        default:
245        case XtalOpt::OT_GULP:
246          ui_combo_queueInterfaces->setCurrentIndex(XtalOpt::QI_LOCAL);
247          break;
248        }
249#endif // ENABLE_SSH
250
251        // Formerly tab_sys stuff. Read from default settings object:
252        settings->beginGroup("xtalopt/sys/");
253        m_opt->description = settings->value("description", "").toString();
254        m_opt->rempath = settings->value("remote/rempath", "").toString();
255        m_opt->filePath = settings->value("file/path", "").toString();
256        m_opt->host = settings->value("remote/host", "").toString();
257        m_opt->port = settings->value("remote/port", 22).toInt();
258        m_opt->username = settings->value("remote/username", "").toString();
259        m_opt->rempath = settings->value("remote/rempath", "").toString();
260        settings->endGroup(); // "xtalopt/sys"
261      }
262    case 2:
263    default:
264      break;
265    }
266
267    m_opt->optimizer()->readSettings(filename);
268    m_opt->queueInterface()->readSettings(filename);
269
270    // Do we need to update the POTCAR info?
271    if (ui_combo_optimizers->currentIndex() == XtalOpt::OT_VASP) {
272      VASPOptimizer *vopt = qobject_cast<VASPOptimizer*>(m_opt->optimizer());
273      if (!vopt->POTCARInfoIsUpToDate(xtalopt->comp.keys())) {
274        if (generateVASP_POTCAR_info()) {
275          vopt->buildPOTCARs();
276        }
277      }
278    }
279
280    updateGUI();
281  }
282
283  void TabEdit::updateEditWidget()
284  {
285    if (!m_isInitialized) {
286      return;
287    }
288
289    QStringList filenames = getTemplateNames();
290    int templateInd = ui_combo_templates->currentIndex();
291    QString templateName = ui_combo_templates->currentText();
292    Q_ASSERT(templateInd >= 0 && templateInd < filenames.size());
293    Q_ASSERT(templateName.compare(filenames.at(templateInd)) == 0);
294
295    if (m_opt->optimizer()->getIDString().compare("VASP") == 0 &&
296        templateName.compare("POTCAR") == 0) {
297
298      if (m_opt->optimizer()->getNumberOfOptSteps() !=
299          ui_list_optStep->count()) {
300        populateOptStepList();
301      }
302
303      int optStepIndex = ui_list_optStep->currentRow();
304      Q_ASSERT(optStepIndex >= 0 &&
305               optStepIndex < m_opt->optimizer()->getNumberOfOptSteps());
306
307      // Display appropriate entry widget.
308      ui_list_edit->setVisible(true);
309      ui_edit_edit->setVisible(false);
310
311      XtalOpt *xtalopt = qobject_cast<XtalOpt*>(m_opt);
312
313      VASPOptimizer *vopt = qobject_cast<VASPOptimizer*>(m_opt->optimizer());
314      // Do we need to update the POTCAR info?
315      if (!vopt->POTCARInfoIsUpToDate(xtalopt->comp.keys())) {
316        if (!generateVASP_POTCAR_info()) {
317          return;
318        }
319        vopt->buildPOTCARs();
320      }
321
322      // Build list in GUI
323      // "POTCAR info" is of type
324      // QList<QHash<QString, QString> >
325      // e.g. a list of hashes containing
326      // [atomic symbol : pseudopotential file] pairs
327      QVariantList potcarInfo = m_opt->optimizer()->getData("POTCAR info").toList();
328      QList<QString> symbols = potcarInfo.at(optStepIndex).toHash().keys();
329      qSort(symbols);
330      ui_list_edit->clear();
331      for (int i = 0; i < symbols.size(); i++) {
332        ui_list_edit->addItem(tr("%1: %2")
333                               .arg(symbols.at(i), 2)
334                               .arg(potcarInfo.at(optStepIndex).toHash()[symbols.at(i)].toString()));
335      }
336    }
337    // Default for all templates using text entry
338    else {
339      AbstractEditTab::updateEditWidget();
340    }
341  }
342
343  void TabEdit::appendOptStep()
344  {
345    // Copy the current files into a new entry at the end of the opt step list
346    if (m_opt->optimizer()->getIDString() == "VASP" &&
347        m_opt->optimizer()->getData("POTCAR info").toList().isEmpty()) {
348      QMessageBox::information(m_dialog, "POTCAR info missing!",
349                               "You need to specify POTCAR information "
350                               "before adding more steps!");
351      generateVASP_POTCAR_info();
352    }
353
354    // Rebuild POTCARs if needed
355    if (m_opt->optimizer()->getIDString() == "VASP") {
356      int currentOptStep = ui_list_optStep->currentRow();
357      QVariantList potcarInfo = m_opt->optimizer()->getData("POTCAR info").toList();
358      potcarInfo.append(potcarInfo.at(currentOptStep));
359      m_opt->optimizer()->setData("POTCAR info", potcarInfo);
360      qobject_cast<VASPOptimizer*>(m_opt->optimizer())->buildPOTCARs();
361    }
362
363    AbstractEditTab::appendOptStep();
364
365    populateOptStepList();
366  }
367
368  void TabEdit::removeCurrentOptStep()
369  {
370    int currentOptStep = ui_list_optStep->currentRow();
371
372    if (VASPOptimizer *vasp = qobject_cast<VASPOptimizer*>
373        (m_opt->optimizer())) {
374      QList<QVariant> sl = vasp->getData("POTCAR info").toList();
375      Q_ASSERT(sl.size() >= currentOptStep + 1);
376      sl.removeAt(currentOptStep);
377      vasp->setData("POTCAR info", sl);
378      vasp->buildPOTCARs();
379    }
380
381    GlobalSearch::AbstractEditTab::removeCurrentOptStep();
382
383    populateOptStepList();
384  }
385
386  void TabEdit::changePOTCAR(QListWidgetItem *item)
387  {
388    QSettings settings; // Already set up in avogadro/src/main.cpp
389
390    // Get symbol and filename
391    QStringList strl = item->text().split(":");
392    QString symbol   = strl.at(0).trimmed();
393    QString filename = strl.at(1).trimmed();
394
395    QStringList files;
396    QString path = settings.value("xtalopt/templates/potcarPath", "").toString();
397    QFileDialog dialog (NULL, QString("Select pot file for atom %1").arg(symbol), path);
398    dialog.selectFile(filename);
399    dialog.setFileMode(QFileDialog::ExistingFile);
400    if (dialog.exec()) {
401      files = dialog.selectedFiles();
402      if (files.size() != 1) { return;} // Only one file per element
403      filename = files.first();
404      settings.setValue("xtalopt/templates/potcarPath", dialog.directory().absolutePath());
405    }
406    else { return;} // User cancel file selection.
407    // "POTCAR info" is of type
408    // QList<QHash<QString, QString> >
409    // e.g. a list of hashes containing
410    // [atomic symbol : pseudopotential file] pairs
411    QVariantList potcarInfo = m_opt->optimizer()->getData("POTCAR info").toList();
412    QVariantHash hash = potcarInfo.at(ui_list_optStep->currentRow()).toHash();
413    hash.insert(symbol,QVariant(filename));
414    potcarInfo.replace(ui_list_optStep->currentRow(), hash);
415    m_opt->optimizer()->setData("POTCAR info", potcarInfo);
416    qobject_cast<VASPOptimizer*>(m_opt->optimizer())->buildPOTCARs();
417    updateEditWidget();
418  }
419
420  bool TabEdit::generateVASP_POTCAR_info()
421  {
422    XtalOpt *xtalopt = qobject_cast<XtalOpt*>(m_opt);
423    QSettings settings; // Already set up in avogadro/src/main.cpp
424    QString path = settings.value("xtalopt/templates/potcarPath", "").toString();
425    QVariantList potcarInfo;
426
427    // Generate list of symbols
428    QList<QString> symbols;
429    QList<uint> atomicNums = xtalopt->comp.keys();
430    qSort(atomicNums);
431
432    for (int i = 0; i < atomicNums.size(); i++)
433      symbols.append(OpenBabel::etab.GetSymbol(atomicNums.at(i)));
434    qSort(symbols);
435    QStringList files;
436    QString filename;
437    QVariantHash hash;
438    for (int i = 0; i < symbols.size(); i++) {
439      QString path = settings.value("xtalopt/templates/potcarPath", "").toString();
440      QFileDialog dialog (NULL, QString("Select pot file for atom %1").arg(symbols.at(i)), path);
441      dialog.selectFile(path + "/" + symbols.at(i));
442      dialog.setFileMode(QFileDialog::ExistingFile);
443      if (dialog.exec()) {
444        files = dialog.selectedFiles();
445        if (files.size() != 1) { // Ask again!
446          i--;
447          continue;
448        }
449        filename = files.first();
450        settings.setValue("xtalopt/templates/potcarPath", dialog.directory().absolutePath());
451      }
452      else {
453        // User cancel file selection. Set template selection combo to
454        // something else so the list will remain empty and be
455        // detected when the search starts. Ref ticket 79.
456        int curInd = ui_combo_templates->currentIndex();
457        int maxInd = ui_combo_templates->count() - 1;
458        int newInd = (curInd == maxInd) ? 0 : maxInd;
459        ui_combo_templates->setCurrentIndex(newInd);
460        return false;
461      }
462      hash.insert(symbols.at(i), QVariant(filename));
463    }
464
465    for (int i = 0; i < m_opt->optimizer()->getNumberOfOptSteps(); i++) {
466      potcarInfo.append(QVariant(hash));
467    }
468
469    // Set composition in optimizer
470    QVariantList toOpt;
471    for (int i = 0; i < atomicNums.size(); i++) {
472      toOpt.append(atomicNums.at(i));
473    }
474    m_opt->optimizer()->setData("Composition", toOpt);
475
476    // Set POTCAR info
477    m_opt->optimizer()->setData("POTCAR info", QVariant(potcarInfo));
478
479    updateEditWidget();
480    return true;
481  }
482}
Note: See TracBrowser for help on using the browser.