root/src/xtalopt/ui/tab_edit.cpp @ 06f244abd607a7c31b6ed64e2a2c378638e727d2

Revision 06f244abd607a7c31b6ed64e2a2c378638e727d2, 19.1 KB (checked in by David C. Lonie <loniedavid@…>, 13 months ago)

Added a preoptimization queue for MolecularXtals?.

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