1 /******************************************************************************
2 
3   This source file is part of the Avogadro project.
4 
5   Copyright 2018 Kitware, Inc.
6 
7   This source code is released under the New BSD License, (the "License").
8 
9   Unless required by applicable law or agreed to in writing, software
10   distributed under the License is distributed on an "AS IS" BASIS,
11   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   See the License for the specific language governing permissions and
13   limitations under the License.
14 
15 ******************************************************************************/
16 
17 #include "openmminputdialog.h"
18 
19 #include <avogadro/core/atom.h>
20 #include <avogadro/core/bond.h>
21 #include <avogadro/core/elements.h>
22 
23 #include <avogadro/io/fileformat.h>
24 #include <avogadro/io/fileformatmanager.h>
25 
26 #include <avogadro/qtgui/molecule.h>
27 
28 #include <QtWidgets/QFileDialog>
29 #include <QtWidgets/QMessageBox>
30 #include <QtWidgets/QTextEdit>
31 
32 #include <QtCore/QDebug>
33 #include <QtCore/QDir>
34 #include <QtCore/QFile>
35 #include <QtCore/QHash>
36 #include <QtCore/QPointer>
37 #include <QtCore/QString>
38 #include <QtCore/QTextStream>
39 
40 namespace Avogadro {
41 namespace QtPlugins {
42 
OpenMMInputDialog(QWidget * parent,Qt::WindowFlags flag)43 OpenMMInputDialog::OpenMMInputDialog(QWidget* parent, Qt::WindowFlags flag)
44   : QDialog(parent, flag), m_molecule(nullptr),
45 
46     m_forceFieldType(amber99sbildn), m_title("Title"), m_savePath(""),
47     m_waterModelType(tip3p), m_nonBondedType(PME),
48 
49     m_constraintType(HBonds), m_integratorType(Langevin),
50     m_barostatType(NoBarostat),
51 
52     m_deviceIndex(1), m_openclPlatformIndex(1), m_rigidWater(0),
53     m_temperature(298.15), m_generationTemperature(298.15),
54     m_nonBondedCutoff(1.0),
55 
56     m_timeStep(2.0), m_ewaldTolerance(0.0005), m_constraintTolerance(0.00001),
57     m_reportInterval(1000), m_equilibriationSteps(100), m_productionSteps(1000),
58     m_errorTolerance(0.0001), m_collisionRate(1.0), m_pressure(1.0),
59     m_barostatInterval(25),
60 
61     m_dumpStep(1),
62 
63     m_velocityDistRandom(0), m_platformType(CUDA),
64     m_precisionType(mixedPrecision), m_thermoInterval(50),
65 
66     m_minimize(0), m_minimizeSteps(1000), m_DCDReporter(true),
67     m_PDBReporter(false), m_stateDataReporter(true),
68 
69     m_output(), m_dirty(false), m_warned(false), readData(false),
70 
71     m_jobEdit(nullptr), m_moleculeEdit(nullptr)
72 {
73   ui.setupUi(this);
74   m_jobFileName =
75     (ui.jobScriptEdit->text().isEmpty() ? ui.jobScriptEdit->placeholderText()
76                                         : ui.jobScriptEdit->text()) +
77     ".py";
78   m_inputCoordFileName =
79     (ui.inputCoordEdit->text().isEmpty() ? ui.inputCoordEdit->placeholderText()
80                                          : ui.inputCoordEdit->text());
81   m_topologyFileName =
82     (ui.inputTopEdit->text().isEmpty() ? ui.inputTopEdit->placeholderText()
83                                        : ui.inputTopEdit->text());
84 
85   // Connect the GUI elements to the correct slots
86   connect(ui.jobScriptEdit, SIGNAL(textChanged(QString)), this,
87           SLOT(setScriptName()));
88   connect(ui.inputCoordEdit, SIGNAL(textChanged(QString)), this,
89           SLOT(setInputCoordName()));
90   connect(ui.forceFieldCombo, SIGNAL(currentIndexChanged(int)), this,
91           SLOT(setForceField(int)));
92   connect(ui.constraintsCombo, SIGNAL(currentIndexChanged(int)), this,
93           SLOT(setConstraintType(int)));
94   connect(ui.waterModelCombo, SIGNAL(currentIndexChanged(int)), this,
95           SLOT(setWaterModelType(int)));
96   connect(ui.nonBondedMethodCombo, SIGNAL(currentIndexChanged(int)), this,
97           SLOT(setNonBondedType(int)));
98   connect(ui.integratorCombo, SIGNAL(currentIndexChanged(int)), this,
99           SLOT(setIntegratorType(int)));
100   connect(ui.barostatCombo, SIGNAL(currentIndexChanged(int)), this,
101           SLOT(setBarostatType(int)));
102   connect(ui.inputTopEdit, SIGNAL(textChanged(QString)), this,
103           SLOT(setTopologyName()));
104   connect(ui.rigidWaterCombo, SIGNAL(currentIndexChanged(int)), this,
105           SLOT(setRigidWater(int)));
106   connect(ui.temperatureSpin, SIGNAL(valueChanged(double)), this,
107           SLOT(setTemperature(double)));
108   connect(ui.generationTemperatureSpin, SIGNAL(valueChanged(double)), this,
109           SLOT(setGenerationTemperature(double)));
110   connect(ui.nonBondedCutoffSpin, SIGNAL(valueChanged(double)), this,
111           SLOT(setNonBondedCutoff(double)));
112   connect(ui.stepSpin, SIGNAL(valueChanged(double)), this,
113           SLOT(setTimeStep(double)));
114   connect(ui.ewaldToleranceSpin, SIGNAL(valueChanged(double)), this,
115           SLOT(setEwaldTolerance(double)));
116   connect(ui.constraintToleranceSpin, SIGNAL(valueChanged(double)), this,
117           SLOT(setConstraintTolerance(double)));
118   connect(ui.reportIntervalSpin, SIGNAL(valueChanged(int)), this,
119           SLOT(setReportInterval(int)));
120   connect(ui.equilibriationStepsSpin, SIGNAL(valueChanged(int)), this,
121           SLOT(setEquilibriationSteps(int)));
122   connect(ui.productionStepsSpin, SIGNAL(valueChanged(int)), this,
123           SLOT(setProductionSteps(int)));
124   connect(ui.deviceIndexSpin, SIGNAL(valueChanged(int)), this,
125           SLOT(setDeviceIndex(int)));
126   connect(ui.openCLIndexSpin, SIGNAL(valueChanged(int)), this,
127           SLOT(setOpenCLPlatformIndex(int)));
128   connect(ui.errorTolSpin, SIGNAL(valueChanged(double)), this,
129           SLOT(setErrorTolerance(double)));
130   connect(ui.collisionRateSpin, SIGNAL(valueChanged(double)), this,
131           SLOT(setCollisionRate(double)));
132   connect(ui.pressureSpin, SIGNAL(valueChanged(double)), this,
133           SLOT(setPressure(double)));
134   connect(ui.barostatIntervalSpin, SIGNAL(valueChanged(int)), this,
135           SLOT(setBarostatInterval(int)));
136   connect(ui.minimizeCombo, SIGNAL(currentIndexChanged(int)), this,
137           SLOT(setMinimize(int)));
138   connect(ui.minimizeStepsSpin, SIGNAL(valueChanged(int)), this,
139           SLOT(setMinimizeSteps(int)));
140   connect(ui.initVelCombo, SIGNAL(currentIndexChanged(int)), this,
141           SLOT(setVelocityDistRandom(int)));
142   connect(ui.platformCombo, SIGNAL(currentIndexChanged(int)), this,
143           SLOT(setPlatformType(int)));
144   connect(ui.precisionCombo, SIGNAL(currentIndexChanged(int)), this,
145           SLOT(setPrecisionType(int)));
146   connect(ui.dcdCheck, SIGNAL(toggled(bool)), this, SLOT(setDCDReporter(bool)));
147   connect(ui.pdbCheck, SIGNAL(toggled(bool)), this, SLOT(setPDBReporter(bool)));
148   connect(ui.stateDataCheck, SIGNAL(toggled(bool)), this,
149           SLOT(setStateDataReporter(bool)));
150 
151   connect(ui.stepIndexCheck, SIGNAL(toggled(bool)), this,
152           SLOT(setStepIndexBoolean(bool)));
153   connect(ui.timeCheck, SIGNAL(toggled(bool)), this,
154           SLOT(setTimeBoolean(bool)));
155   connect(ui.speedCheck, SIGNAL(toggled(bool)), this,
156           SLOT(setSpeedBoolean(bool)));
157   connect(ui.progressCheck, SIGNAL(toggled(bool)), this,
158           SLOT(setProgressBoolean(bool)));
159   connect(ui.potentialEnergyCheck, SIGNAL(toggled(bool)), this,
160           SLOT(setPotentialEnergyBoolean(bool)));
161   connect(ui.kineticEnergyCheck, SIGNAL(toggled(bool)), this,
162           SLOT(setKineticEnergyBoolean(bool)));
163   connect(ui.totalEnergyCheck, SIGNAL(toggled(bool)), this,
164           SLOT(setTotalEnergyBoolean(bool)));
165   connect(ui.temperatureCheck, SIGNAL(toggled(bool)), this,
166           SLOT(setTemperatureBoolean(bool)));
167   connect(ui.volumeCheck, SIGNAL(toggled(bool)), this,
168           SLOT(setVolumeBoolean(bool)));
169   connect(ui.densityCheck, SIGNAL(toggled(bool)), this,
170           SLOT(setDensityBoolean(bool)));
171 
172   connect(ui.generateButton, SIGNAL(clicked()), this, SLOT(generateClicked()));
173   connect(ui.resetButton, SIGNAL(clicked()), this, SLOT(resetClicked()));
174 
175   connect(ui.enableFormButton, SIGNAL(clicked()), this,
176           SLOT(enableFormClicked()));
177 
178   QSettings settings;
179   readSettings(settings);
180 
181   resetClicked();
182 
183   // Generate an initial preview of the input deck
184   updatePreviewText();
185   addMoleculeDataTab();
186 }
187 
~OpenMMInputDialog()188 OpenMMInputDialog::~OpenMMInputDialog()
189 {
190   QSettings settings;
191   writeSettings(settings);
192 }
193 
showEvent(QShowEvent *)194 void OpenMMInputDialog::showEvent(QShowEvent*)
195 {
196   updatePreviewText();
197   addMoleculeDataTab();
198 }
199 
updatePreviewText()200 void OpenMMInputDialog::updatePreviewText()
201 {
202   if (!isVisible())
203     return;
204 
205   int jobTabPosition = 0;
206 
207   // Store the currently displayed tab
208   int currIndex = ui.tabWidget->currentIndex();
209 
210   // Generate the input deck and display it
211   if (m_dirty) {
212     QString message =
213       tr("Would you like to update the preview text, losing all "
214          "changes made in the OpenMM input deck preview pane?");
215     int response = QMessageBox::question(
216       this, tr("Overwrite modified input files?"), message,
217       QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
218 
219     if (static_cast<QMessageBox::StandardButton>(response) == QMessageBox::No) {
220       return;
221     }
222   }
223 
224   ui.tabWidget->removeTab(jobTabPosition);
225 
226   m_jobEdit = new QTextEdit(this);
227   m_jobEdit->setObjectName(m_jobFileName);
228   m_jobEdit->setFontFamily("monospace");
229   connect(m_jobEdit, SIGNAL(textChanged()), this, SLOT(textEditModified()));
230   m_jobEdit->setText(generateInputDeck());
231   ui.tabWidget->insertTab(jobTabPosition, m_jobEdit, m_jobFileName);
232   deckDirty(false);
233 
234   // Restore current tab
235   ui.tabWidget->setCurrentIndex(currIndex);
236 }
237 
addMoleculeDataTab()238 void OpenMMInputDialog::addMoleculeDataTab()
239 {
240   int molTabPosition = 1;
241   if (m_molecule) {
242     ui.tabWidget->removeTab(molTabPosition);
243     std::string molOutput,
244       extension = m_inputCoordFileName.split(".").back().toStdString();
245 
246     bool writeSDF = Io::FileFormatManager::instance().writeString(
247       *m_molecule, molOutput, extension);
248     if (writeSDF) {
249       m_moleculeEdit = new QTextEdit(this);
250       m_moleculeEdit->setObjectName(m_inputCoordFileName);
251       m_moleculeEdit->setFontFamily("monospace");
252       m_moleculeEdit->setText(QString::fromStdString(molOutput));
253       ui.tabWidget->insertTab(molTabPosition, m_moleculeEdit,
254                               m_inputCoordFileName);
255     }
256   }
257 }
258 
textEditModified()259 void OpenMMInputDialog::textEditModified()
260 {
261   if (QTextEdit* edit = qobject_cast<QTextEdit*>(sender())) {
262     if (edit->document()->isModified()) {
263       deckDirty(true);
264     } else {
265       deckDirty(false);
266     }
267   }
268 }
269 
resetClicked()270 void OpenMMInputDialog::resetClicked()
271 {
272   // Reset the form to defaults
273   deckDirty(false);
274 
275   // 1st subdivision
276   ui.precisionCombo->setCurrentIndex(1);
277   ui.forceFieldCombo->setCurrentIndex(2);
278   ui.waterModelCombo->setCurrentIndex(1);
279   ui.platformCombo->setCurrentIndex(3);
280   setPlatformType(3);
281 
282   // 2nd subdivision
283   ui.ewaldToleranceSpin->setValue(0.0005);
284   ui.constraintToleranceSpin->setValue(0.00001);
285   ui.nonBondedCutoffSpin->setValue(1.0);
286   ui.generationTemperatureSpin->setValue(298.15);
287   ui.nonBondedMethodCombo->setCurrentIndex(4);
288   setNonBondedType(4);
289   ui.constraintsCombo->setCurrentIndex(1);
290   setConstraintType(1);
291   ui.rigidWaterCombo->setCurrentIndex(0);
292   setRigidWater(0);
293   ui.initVelCombo->setCurrentIndex(0);
294   setVelocityDistRandom(0);
295 
296   // 3rd subdivision
297   ui.stepSpin->setValue(2.0);
298   ui.errorTolSpin->setValue(0.0001);
299   ui.collisionRateSpin->setValue(1.0);
300   ui.temperatureSpin->setValue(298.15);
301   ui.pressureSpin->setValue(1.0);
302   ui.barostatIntervalSpin->setValue(25);
303   ui.barostatCombo->setCurrentIndex(0);
304   setBarostatType(0);
305   ui.integratorCombo->setCurrentIndex(0);
306   setIntegratorType(0);
307 
308   // 4th subdivision
309   ui.minimizeCombo->setCurrentIndex(0);
310   ui.reportIntervalSpin->setValue(1000);
311   ui.minimizeStepsSpin->setValue(1000);
312   ui.productionStepsSpin->setValue(1000);
313   ui.equilibriationStepsSpin->setValue(100);
314   ui.stepIndexCheck->setChecked(true);
315   ui.timeCheck->setChecked(false);
316   ui.speedCheck->setChecked(true);
317   ui.progressCheck->setChecked(true);
318   ui.potentialEnergyCheck->setChecked(true);
319   ui.kineticEnergyCheck->setChecked(false);
320   ui.totalEnergyCheck->setChecked(false);
321   ui.temperatureCheck->setChecked(true);
322   ui.volumeCheck->setChecked(false);
323   ui.densityCheck->setChecked(false);
324   // Unfortunately, setChecked() does not emit toggled() signal
325   // So the slots have to be invoked
326   setStepIndexBoolean(true);
327   setTimeBoolean(false);
328   setSpeedBoolean(true);
329   setProgressBoolean(true);
330   setPotentialEnergyBoolean(true);
331   setKineticEnergyBoolean(false);
332   setTotalEnergyBoolean(false);
333   setTemperatureBoolean(true);
334   setVolumeBoolean(false);
335   setDensityBoolean(false);
336 
337   ui.stateDataCheck->setChecked(true);
338   ui.dcdCheck->setChecked(true);
339   ui.pdbCheck->setChecked(false);
340 
341   updatePreviewText();
342   addMoleculeDataTab();
343 }
344 
generateClicked()345 void OpenMMInputDialog::generateClicked()
346 {
347   QSettings settings;
348   QString directory =
349     settings.value("openmmInput/outputDirectory", QDir::homePath()).toString();
350   if (directory.isEmpty())
351     directory = QDir::homePath();
352   directory = QFileDialog::getExistingDirectory(
353     this, tr("Select output directory"), directory);
354 
355   // User cancel:
356   if (directory.isNull())
357     return;
358 
359   settings.setValue("openmmInput/outputDirectory", directory);
360   QDir dir(directory);
361 
362   // Check for problems:
363   QStringList errors;
364   bool fatalError = false;
365 
366   do { // Do/while to break on fatal errors
367     if (!dir.exists()) {
368       errors << tr("%1: Directory does not exist!").arg(dir.absolutePath());
369       fatalError = true;
370       break;
371     }
372 
373     if (!dir.isReadable()) {
374       errors << tr("%1: Directory cannot be read!").arg(dir.absolutePath());
375       fatalError = true;
376       break;
377     }
378 
379     QFileInfo jobFileInfo(dir.absoluteFilePath(m_jobFileName));
380 
381     if (jobFileInfo.exists()) {
382       errors << tr("%1: File will be overwritten.")
383                   .arg(jobFileInfo.absoluteFilePath());
384     }
385 
386     // Attempt to open the file for writing
387     if (!QFile(jobFileInfo.absoluteFilePath()).open(QFile::WriteOnly)) {
388       errors
389         << tr("%1: File is not writable.").arg(jobFileInfo.absoluteFilePath());
390       fatalError = true;
391       break;
392     }
393 
394     QFileInfo molFileInfo(dir.absoluteFilePath(m_inputCoordFileName));
395 
396     if (molFileInfo.exists()) {
397       errors << tr("%1: File will be overwritten.")
398                   .arg(molFileInfo.absoluteFilePath());
399     }
400 
401     // Attempt to open the file for writing
402     if (!QFile(molFileInfo.absoluteFilePath()).open(QFile::WriteOnly)) {
403       errors
404         << tr("%1: File is not writable.").arg(molFileInfo.absoluteFilePath());
405       fatalError = true;
406       break;
407     }
408   } while (false); // only run once
409 
410   // Handle fatal errors:
411   if (fatalError) {
412     QString formattedError;
413     switch (errors.size()) {
414       case 0:
415         formattedError =
416           tr("The input files cannot be written due to an unknown error.");
417         break;
418       case 1:
419         formattedError =
420           tr("The input files cannot be written:\n\n%1").arg(errors.first());
421         break;
422       default: {
423         // If a fatal error occured, it will be last one in the list. Pop it off
424         // and tell the user that it was the reason we had to stop.
425         QString fatal = errors.last();
426         QStringList tmp(errors);
427         tmp.pop_back();
428         formattedError =
429           tr("The input files cannot be written:\n\n%1\n\nWarnings:\n\n%2")
430             .arg(fatal, tmp.join("\n"));
431         break;
432       }
433     }
434     QMessageBox::critical(this, tr("Output Error"), formattedError);
435     return;
436   }
437 
438   // Non-fatal errors:
439   if (!errors.isEmpty()) {
440     QString formattedError = tr("Warning:\n\n%1\n\nWould you like to continue?")
441                                .arg(errors.join("\n"));
442 
443     QMessageBox::StandardButton reply =
444       QMessageBox::warning(this, tr("Write input files"), formattedError,
445                            QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
446 
447     if (reply != QMessageBox::Yes)
448       return;
449   }
450 
451   bool success = false;
452 
453   if (m_jobEdit && m_moleculeEdit) {
454     QFile jobFile(dir.absoluteFilePath(m_jobFileName));
455     if (jobFile.open(QFile::WriteOnly | QFile::Text)) {
456       if (jobFile.write(m_jobEdit->toPlainText().toLocal8Bit()) > 0) {
457         success = true;
458       }
459       jobFile.close();
460     }
461 
462     if (!success) {
463       QMessageBox::critical(
464         this, tr("Output Error"),
465         tr("Failed to write to file %1.").arg(jobFile.fileName()));
466     }
467 
468     QFile molFile(dir.absoluteFilePath(m_inputCoordFileName));
469     if (molFile.open(QFile::WriteOnly | QFile::Text)) {
470       if (molFile.write(m_moleculeEdit->toPlainText().toLocal8Bit()) > 0) {
471         success = true;
472       }
473       molFile.close();
474     }
475 
476     if (!success) {
477       QMessageBox::critical(
478         this, tr("Output Error"),
479         tr("Failed to write to file %1.").arg(molFile.fileName()));
480     }
481   }
482 }
483 
enableFormClicked()484 void OpenMMInputDialog::enableFormClicked()
485 {
486   updatePreviewText();
487 }
488 
setScriptName()489 void OpenMMInputDialog::setScriptName()
490 {
491   m_jobFileName =
492     (ui.jobScriptEdit->text().isEmpty() ? ui.jobScriptEdit->placeholderText()
493                                         : ui.jobScriptEdit->text()) +
494     ".py";
495   updatePreviewText();
496 }
497 
setInputCoordName()498 void OpenMMInputDialog::setInputCoordName()
499 {
500   ui.inputCoordEdit->setStyleSheet("");
501   m_inputCoordFileName =
502     (ui.inputCoordEdit->text().isEmpty() ? ui.inputCoordEdit->placeholderText()
503                                          : ui.inputCoordEdit->text());
504   QString ext = m_inputCoordFileName.split(".").back();
505   if (ext == tr("inpcrd") || ext == tr("gro")) {
506     ui.forceFieldCombo->setEnabled(false);
507     ui.inputTopEdit->setEnabled(true);
508     if (ext == tr("inpcrd"))
509       ui.inputTopEdit->setPlaceholderText(tr("input.prmtop"));
510     else if (ext == tr("gro")) {
511       ui.inputTopEdit->setPlaceholderText(tr("input.top"));
512     }
513     updatePreviewText();
514   } else if (ext == tr("pdb")) {
515     ui.forceFieldCombo->setEnabled(true);
516     ui.inputTopEdit->setEnabled(false);
517     updatePreviewText();
518   } else {
519     ui.forceFieldCombo->setEnabled(false);
520     ui.inputTopEdit->setEnabled(false);
521     ui.inputCoordEdit->setStyleSheet("color: #FF0000");
522   }
523   addMoleculeDataTab();
524 }
525 
setTopologyName()526 void OpenMMInputDialog::setTopologyName()
527 {
528   ui.inputCoordEdit->setStyleSheet("");
529   m_topologyFileName =
530     (ui.inputTopEdit->text().isEmpty() ? ui.inputTopEdit->placeholderText()
531                                        : ui.inputTopEdit->text());
532   QString ext = m_topologyFileName.split(".").back();
533   QString extCoord = m_inputCoordFileName.split(".").back();
534   if (extCoord == tr("inpcrd")) {
535     if (ext != tr("prmtop")) {
536       ui.inputCoordEdit->setStyleSheet("color: #FF0000");
537     }
538   } else if (extCoord == tr("gro")) {
539     if (ext != tr("top")) {
540       ui.inputCoordEdit->setStyleSheet("color: #FF0000");
541     }
542   }
543   updatePreviewText();
544 }
545 
setForceField(int n)546 void OpenMMInputDialog::setForceField(int n)
547 {
548   m_forceFieldType = (OpenMMInputDialog::forceFieldType)n;
549   ui.forceFieldCombo->setEnabled(true);
550   updatePreviewText();
551 }
552 
setConstraintType(int n)553 void OpenMMInputDialog::setConstraintType(int n)
554 {
555   m_constraintType = static_cast<OpenMMInputDialog::constraintType>(n);
556   ui.constraintsCombo->setEnabled(true);
557   if (m_constraintType == None) {
558     ui.constraintToleranceSpin->setEnabled(false);
559   } else {
560     ui.constraintToleranceSpin->setEnabled(true);
561   }
562   updatePreviewText();
563 }
564 
setWaterModelType(int n)565 void OpenMMInputDialog::setWaterModelType(int n)
566 {
567   m_waterModelType = static_cast<OpenMMInputDialog::waterModelType>(n);
568   ui.waterModelCombo->setEnabled(true);
569   updatePreviewText();
570 }
571 
setNonBondedType(int n)572 void OpenMMInputDialog::setNonBondedType(int n)
573 {
574   m_nonBondedType = static_cast<OpenMMInputDialog::nonBondedType>(n);
575   ui.nonBondedMethodCombo->setEnabled(true);
576   if (m_nonBondedType == NoCutoff) {
577     ui.nonBondedCutoffSpin->setEnabled(false);
578     ui.ewaldToleranceSpin->setEnabled(false);
579   } else if (m_nonBondedType == CutoffPeriodic ||
580              m_nonBondedType == CutoffNonPeriodic) {
581     ui.nonBondedCutoffSpin->setEnabled(true);
582     ui.ewaldToleranceSpin->setEnabled(false);
583   } else if (m_nonBondedType == Ewald || m_nonBondedType == PME) {
584     ui.nonBondedCutoffSpin->setEnabled(true);
585     ui.ewaldToleranceSpin->setEnabled(true);
586   }
587   updatePreviewText();
588 }
589 
setIntegratorType(int n)590 void OpenMMInputDialog::setIntegratorType(int n)
591 {
592   m_integratorType = static_cast<OpenMMInputDialog::integratorType>(n);
593   ui.integratorCombo->setEnabled(true);
594   if (m_integratorType == Langevin || m_integratorType == Brownian ||
595       m_integratorType == VariableLangevin) {
596     if (m_integratorType == Langevin || m_integratorType == Brownian) {
597       ui.stepSpin->setEnabled(true);
598       ui.errorTolSpin->setEnabled(false);
599     } else if (m_integratorType == VariableLangevin) {
600       ui.stepSpin->setEnabled(false);
601       ui.errorTolSpin->setEnabled(true);
602     }
603     ui.collisionRateSpin->setEnabled(true);
604     ui.temperatureSpin->setEnabled(true);
605     ui.barostatCombo->setEnabled(true);
606     if (m_barostatType == NoBarostat) {
607       ui.pressureSpin->setEnabled(false);
608       ui.barostatIntervalSpin->setEnabled(false);
609     } else {
610       ui.pressureSpin->setEnabled(true);
611       ui.barostatIntervalSpin->setEnabled(true);
612     }
613   } else if (m_integratorType == Verlet || m_integratorType == VariableVerlet) {
614     if (m_integratorType == Verlet) {
615       ui.stepSpin->setEnabled(true);
616       ui.errorTolSpin->setEnabled(false);
617     } else if (m_integratorType == VariableVerlet) {
618       ui.stepSpin->setEnabled(false);
619       ui.errorTolSpin->setEnabled(true);
620     }
621     ui.collisionRateSpin->setEnabled(false);
622     ui.temperatureSpin->setEnabled(false);
623     ui.barostatCombo->setEnabled(false);
624     ui.pressureSpin->setEnabled(false);
625     ui.barostatIntervalSpin->setEnabled(false);
626   }
627   updatePreviewText();
628 }
629 
setBarostatType(int n)630 void OpenMMInputDialog::setBarostatType(int n)
631 {
632   m_barostatType = static_cast<OpenMMInputDialog::barostatType>(n);
633   ui.barostatCombo->setEnabled(true);
634   if (m_barostatType == NoBarostat) {
635     ui.pressureSpin->setEnabled(false);
636     ui.barostatIntervalSpin->setEnabled(false);
637   } else {
638     ui.pressureSpin->setEnabled(true);
639     ui.barostatIntervalSpin->setEnabled(true);
640   }
641   updatePreviewText();
642 }
643 
setMolecule(QtGui::Molecule * molecule)644 void OpenMMInputDialog::setMolecule(QtGui::Molecule* molecule)
645 {
646   // Disconnect the old molecule first...
647   if (molecule == m_molecule)
648     return;
649 
650   if (m_molecule)
651     m_molecule->disconnect(this);
652 
653   m_molecule = molecule;
654   // Update the preview text whenever primitives are changed
655   connect(molecule, SIGNAL(changed(unsigned int)), SLOT(updatePreviewText()));
656   updatePreviewText();
657 }
658 
setRigidWater(int n)659 void OpenMMInputDialog::setRigidWater(int n)
660 {
661   m_rigidWater = n;
662   ui.rigidWaterCombo->setEnabled(true);
663   updatePreviewText();
664 }
665 
setMinimize(int n)666 void OpenMMInputDialog::setMinimize(int n)
667 {
668   m_minimize = n;
669   ui.minimizeCombo->setEnabled(true);
670   updatePreviewText();
671 }
672 
setMinimizeSteps(int n)673 void OpenMMInputDialog::setMinimizeSteps(int n)
674 {
675   m_minimizeSteps = n;
676   ui.minimizeStepsSpin->setEnabled(true);
677   updatePreviewText();
678 }
679 
setTemperature(double n)680 void OpenMMInputDialog::setTemperature(double n)
681 {
682   m_temperature = n;
683   ui.temperatureSpin->setEnabled(true);
684   updatePreviewText();
685 }
686 
setNonBondedCutoff(double n)687 void OpenMMInputDialog::setNonBondedCutoff(double n)
688 {
689   m_nonBondedCutoff = n;
690   ui.nonBondedCutoffSpin->setEnabled(true);
691   updatePreviewText();
692 }
693 
setTimeStep(double n)694 void OpenMMInputDialog::setTimeStep(double n)
695 {
696   m_timeStep = n;
697   ui.stepSpin->setEnabled(true);
698   updatePreviewText();
699 }
700 
setEwaldTolerance(double n)701 void OpenMMInputDialog::setEwaldTolerance(double n)
702 {
703   m_ewaldTolerance = n;
704   ui.ewaldToleranceSpin->setEnabled(true);
705   updatePreviewText();
706 }
707 
setConstraintTolerance(double n)708 void OpenMMInputDialog::setConstraintTolerance(double n)
709 {
710   m_constraintTolerance = n;
711   ui.constraintToleranceSpin->setEnabled(true);
712   updatePreviewText();
713 }
714 
setReportInterval(int n)715 void OpenMMInputDialog::setReportInterval(int n)
716 {
717   m_reportInterval = n;
718   ui.reportIntervalSpin->setEnabled(true);
719   updatePreviewText();
720 }
721 
setEquilibriationSteps(int n)722 void OpenMMInputDialog::setEquilibriationSteps(int n)
723 {
724   m_equilibriationSteps = n;
725   ui.equilibriationStepsSpin->setEnabled(true);
726   updatePreviewText();
727 }
728 
setProductionSteps(int n)729 void OpenMMInputDialog::setProductionSteps(int n)
730 {
731   m_productionSteps = n;
732   ui.productionStepsSpin->setEnabled(true);
733   updatePreviewText();
734 }
735 
setDeviceIndex(int n)736 void OpenMMInputDialog::setDeviceIndex(int n)
737 {
738   m_deviceIndex = n;
739   ui.deviceIndexSpin->setEnabled(true);
740   updatePreviewText();
741 }
742 
setOpenCLPlatformIndex(int n)743 void OpenMMInputDialog::setOpenCLPlatformIndex(int n)
744 {
745   m_openclPlatformIndex = n;
746   ui.openCLIndexSpin->setEnabled(true);
747   updatePreviewText();
748 }
749 
setErrorTolerance(double n)750 void OpenMMInputDialog::setErrorTolerance(double n)
751 {
752   m_errorTolerance = n;
753   ui.errorTolSpin->setEnabled(true);
754   updatePreviewText();
755 }
756 
setCollisionRate(double n)757 void OpenMMInputDialog::setCollisionRate(double n)
758 {
759   m_collisionRate = n;
760   ui.collisionRateSpin->setEnabled(true);
761   updatePreviewText();
762 }
763 
setPressure(double n)764 void OpenMMInputDialog::setPressure(double n)
765 {
766   m_pressure = n;
767   ui.pressureSpin->setEnabled(true);
768   updatePreviewText();
769 }
770 
setBarostatInterval(int n)771 void OpenMMInputDialog::setBarostatInterval(int n)
772 {
773   m_barostatInterval = n;
774   ui.barostatIntervalSpin->setEnabled(true);
775   updatePreviewText();
776 }
777 
setVelocityDistRandom(int n)778 void OpenMMInputDialog::setVelocityDistRandom(int n)
779 {
780   m_velocityDistRandom = n;
781   ui.initVelCombo->setEnabled(true);
782   if (m_velocityDistRandom == 1) {
783     ui.generationTemperatureSpin->setEnabled(false);
784   } else {
785     ui.generationTemperatureSpin->setEnabled(true);
786   }
787   updatePreviewText();
788 }
789 
setGenerationTemperature(double n)790 void OpenMMInputDialog::setGenerationTemperature(double n)
791 {
792   m_generationTemperature = n;
793   ui.generationTemperatureSpin->setEnabled(true);
794   updatePreviewText();
795 }
796 
setDCDReporter(bool state)797 void OpenMMInputDialog::setDCDReporter(bool state)
798 {
799   m_DCDReporter = state;
800   ui.dcdCheck->setEnabled(true);
801   updatePreviewText();
802 }
803 
setPDBReporter(bool state)804 void OpenMMInputDialog::setPDBReporter(bool state)
805 {
806   m_PDBReporter = state;
807   ui.pdbCheck->setEnabled(true);
808   updatePreviewText();
809 }
810 
setStepIndexBoolean(bool state)811 void OpenMMInputDialog::setStepIndexBoolean(bool state)
812 {
813   m_stepIndex = state;
814   ui.stepIndexCheck->setEnabled(true);
815   updatePreviewText();
816 }
setTimeBoolean(bool state)817 void OpenMMInputDialog::setTimeBoolean(bool state)
818 {
819   m_time = state;
820   ui.timeCheck->setEnabled(true);
821   updatePreviewText();
822 }
setSpeedBoolean(bool state)823 void OpenMMInputDialog::setSpeedBoolean(bool state)
824 {
825   m_speed = state;
826   ui.speedCheck->setEnabled(true);
827   updatePreviewText();
828 }
setProgressBoolean(bool state)829 void OpenMMInputDialog::setProgressBoolean(bool state)
830 {
831   m_progress = state;
832   ui.progressCheck->setEnabled(true);
833   updatePreviewText();
834 }
setPotentialEnergyBoolean(bool state)835 void OpenMMInputDialog::setPotentialEnergyBoolean(bool state)
836 {
837   m_potentialEnergy = state;
838   ui.potentialEnergyCheck->setEnabled(true);
839   updatePreviewText();
840 }
setKineticEnergyBoolean(bool state)841 void OpenMMInputDialog::setKineticEnergyBoolean(bool state)
842 {
843   m_kineticEnergy = state;
844   ui.kineticEnergyCheck->setEnabled(true);
845   updatePreviewText();
846 }
setTotalEnergyBoolean(bool state)847 void OpenMMInputDialog::setTotalEnergyBoolean(bool state)
848 {
849   m_totalEnergy = state;
850   ui.totalEnergyCheck->setEnabled(true);
851   updatePreviewText();
852 }
setTemperatureBoolean(bool state)853 void OpenMMInputDialog::setTemperatureBoolean(bool state)
854 {
855   m_temperature = state;
856   ui.temperatureCheck->setEnabled(true);
857   updatePreviewText();
858 }
setVolumeBoolean(bool state)859 void OpenMMInputDialog::setVolumeBoolean(bool state)
860 {
861   m_volume = state;
862   ui.volumeCheck->setEnabled(true);
863   updatePreviewText();
864 }
setDensityBoolean(bool state)865 void OpenMMInputDialog::setDensityBoolean(bool state)
866 {
867   m_density = state;
868   ui.densityCheck->setEnabled(true);
869   updatePreviewText();
870 }
871 
setStateDataReporter(bool state)872 void OpenMMInputDialog::setStateDataReporter(bool state)
873 {
874   ui.stepIndexCheck->setEnabled(state);
875   ui.timeCheck->setEnabled(state);
876   ui.speedCheck->setEnabled(state);
877   ui.progressCheck->setEnabled(state);
878   ui.potentialEnergyCheck->setEnabled(state);
879   ui.kineticEnergyCheck->setEnabled(state);
880   ui.totalEnergyCheck->setEnabled(state);
881   ui.temperatureCheck->setEnabled(state);
882   ui.volumeCheck->setEnabled(state);
883   ui.densityCheck->setEnabled(state);
884 
885   m_stateDataReporter = state;
886   ui.stateDataCheck->setEnabled(true);
887   updatePreviewText();
888 }
889 
setPlatformType(int n)890 void OpenMMInputDialog::setPlatformType(int n)
891 {
892   m_platformType = static_cast<OpenMMInputDialog::platformType>(n);
893   ui.platformCombo->setEnabled(true);
894   if (m_platformType == Reference || m_platformType == CPU) {
895     ui.precisionCombo->setEnabled(false);
896     ui.deviceIndexSpin->setEnabled(false);
897     ui.openCLIndexSpin->setEnabled(false);
898   } else {
899     ui.precisionCombo->setEnabled(true);
900     ui.deviceIndexSpin->setEnabled(true);
901     if (m_platformType == OpenCL)
902       ui.openCLIndexSpin->setEnabled(true);
903     else
904       ui.openCLIndexSpin->setEnabled(false);
905   }
906   updatePreviewText();
907 }
908 
setPrecisionType(int n)909 void OpenMMInputDialog::setPrecisionType(int n)
910 {
911   m_precisionType = static_cast<OpenMMInputDialog::precisionType>(n);
912   ui.precisionCombo->setEnabled(true);
913   updatePreviewText();
914 }
915 
generateInputDeck()916 QString OpenMMInputDialog::generateInputDeck()
917 {
918   // Generate an input deck based on the settings of the dialog
919   QString buffer;
920   QTextStream scriptStream(&buffer);
921 
922   scriptStream << "############################################################"
923                   "##############\n";
924   scriptStream << "# OpenMM input script generated by Avogadro.\n";
925   scriptStream << "# Builder adapted from OpenMM script builder "
926                   "http://builder.openmm.org.\n";
927   scriptStream << "############################################################"
928                   "##############\n\n";
929   scriptStream << "from __future__ import print_function\n";
930   scriptStream << "from simtk.openmm import app\n";
931   scriptStream << "import simtk.openmm as mm\n";
932   scriptStream << "from simtk import unit\n";
933   scriptStream << "from sys import stdout\n";
934 
935   // first two or three lines, that load up the FF and the pdb
936   // these lines end with the start of the function something.createSystem(
937   QString ext = m_inputCoordFileName.split(".").back();
938   if (ext == tr("pdb")) {
939     scriptStream << "\npdb = app.PDBFile(\'" << m_inputCoordFileName << "\')\n";
940     scriptStream << "forcefield = app.ForceField(\'"
941                  << getForceFieldType(m_forceFieldType) << ".xml\'";
942     scriptStream << ", \'" << getWaterModelType(m_waterModelType) << ".xml\'";
943     scriptStream << ")\n\n";
944     scriptStream << "system = forcefield.createSystem(pdb.topology, ";
945   } else if (ext == tr("inpcrd")) {
946     scriptStream << "\nprmtop = app.AmberPrmtopFile(\'" << m_topologyFileName
947                  << "\')\n";
948     scriptStream << "inpcrd = app.AmberInpcrdFile(\'" << m_inputCoordFileName
949                  << "\')\n\n";
950     scriptStream << "system = prmtop.createSystem(";
951     if (m_waterModelType == implicit) {
952       scriptStream << "implicitSolvent=app.OBC2, ";
953     }
954   } else if (ext == tr("gro")) {
955     scriptStream << "\ngro = app.GromacsGroFile(\'" << m_inputCoordFileName
956                  << "\')\n";
957     scriptStream << "top = app.GromacsTopFile(\'" << m_topologyFileName
958                  << "\')\n\n";
959     scriptStream << "system = top.createSystem(";
960     if (m_waterModelType == implicit) {
961       scriptStream << "implicitSolvent=app.OBC2, ";
962     }
963   } else {
964     // TODO
965   }
966 
967   // options for the system
968   scriptStream << "nonbondedMethod="
969                << "app." << getNonBondedType(m_nonBondedType) << ",";
970   if (m_nonBondedCutoff > 0) {
971     scriptStream << " nonbondedCutoff=" << fixed << qSetRealNumberPrecision(4)
972                  << m_nonBondedCutoff << "*unit.nanometers,";
973   }
974   if (m_constraintType == None) {
975     scriptStream << " constraints=" << getConstraintType(m_constraintType);
976   } else {
977     scriptStream << " constraints="
978                  << "app." << getConstraintType(m_constraintType);
979   }
980   scriptStream << ", rigidWater=" << getRigidWater(m_rigidWater);
981   if (m_nonBondedType == Ewald || m_nonBondedType == PME) {
982     scriptStream << ", ewaldErrorTolerance=" << fixed
983                  << qSetRealNumberPrecision(5) << m_ewaldTolerance;
984   }
985   scriptStream << ")\n";
986 
987   // set the integrator
988   scriptStream << "integrator = mm." << getIntegratorType(m_integratorType)
989                << "Integrator(";
990   if (m_integratorType == Langevin || m_integratorType == Brownian) {
991     scriptStream << m_temperature << "*unit.kelvin, ";
992     scriptStream << m_collisionRate << "/unit.picoseconds, ";
993   }
994   if (m_integratorType == VariableLangevin ||
995       m_integratorType == VariableVerlet) {
996     scriptStream << m_errorTolerance << ")\n";
997   } else {
998     scriptStream << m_timeStep << "*unit.femtoseconds)\n";
999   }
1000   if (m_constraintType != None && m_constraintTolerance > 0) {
1001     scriptStream << "integrator.setConstraintTolerance("
1002                  << m_constraintTolerance << ")\n";
1003   }
1004 
1005   // add a barostat
1006   if (m_barostatType == MonteCarlo) {
1007     scriptStream << "system.addForce(mm.MonteCarloBarostat(" << m_pressure
1008                  << "*unit.atmospheres";
1009     scriptStream << ", " << m_temperature << "*unit.kelvin";
1010     if (m_barostatInterval > 0) {
1011       scriptStream << ", " << m_barostatInterval;
1012     }
1013     scriptStream << "))\n";
1014   }
1015 
1016   // // add a thermostat
1017   // if (m_thermostatType == Andersen) {
1018   //     scriptStream << "system.addForce(mm.AndersenThermostat(" <<
1019   //     m_temperature << "*unit.kelvin"; scriptStream << ", " <<
1020   //     m_collisionRate << "/unit.picoseconds" << "))\n";
1021   // }
1022 
1023   scriptStream << "\n";
1024 
1025   // set the platform options
1026   scriptStream << "platform = mm.Platform.getPlatformByName(\'"
1027                << getPlatformType(m_platformType) << "\')\n";
1028   if (m_platformType == CUDA) {
1029     scriptStream << "properties = {\'CudaPrecision\': \'"
1030                  << getPrecisionType(m_precisionType) << "\'";
1031     if (m_deviceIndex > 0) {
1032       scriptStream << ", \'CudaDeviceIndex\': \'" << m_deviceIndex << "\'";
1033     }
1034     scriptStream << "}\n";
1035   } else if (m_platformType == OpenCL) {
1036     scriptStream << "properties = {\'OpenCLPrecision\': \'"
1037                  << getPrecisionType(m_precisionType) << "\'";
1038     if (m_openclPlatformIndex > 0) {
1039       scriptStream << ", \'OpenCLPlatformIndex\': \'" << m_openclPlatformIndex
1040                    << "\'";
1041     }
1042     if (m_deviceIndex > 0) {
1043       scriptStream << ", ";
1044       if (m_openclPlatformIndex > 0) {
1045         scriptStream << "\n              ";
1046       }
1047       scriptStream << "\'OpenCLDeviceIndex\': \'" << m_deviceIndex << "\'";
1048     }
1049     scriptStream << "}\n";
1050   }
1051 
1052   // create the simulation object
1053   scriptStream << "simulation = app.Simulation("
1054                << (ext == tr("pdb") ? "pdb" : "prmtop")
1055                << ".topology, system, integrator, platform";
1056   if (m_platformType == CUDA || m_platformType == OpenCL) {
1057     scriptStream << ", properties";
1058   }
1059   scriptStream << ")\n";
1060 
1061   if (ext == tr("pdb")) {
1062     scriptStream << "simulation.context.setPositions(pdb.positions)\n\n";
1063   } else if (ext == tr("inpcrd")) {
1064     scriptStream << "simulation.context.setPositions(inpcrd.positions)\n\n";
1065   } else if (ext == tr("gro")) {
1066     scriptStream << "simulation.context.setPositions(gro.positions)\n\n";
1067   } else {
1068     // TODO
1069   }
1070 
1071   // minimize
1072   if (getMinimize(m_minimize) == tr("True")) {
1073     scriptStream << "print('Minimizing...\')\n";
1074     if (m_minimizeSteps == 0) {
1075       scriptStream << "simulation.minimizeEnergy()\n";
1076     } else {
1077       scriptStream << "simulation.minimizeEnergy(maxIterations="
1078                    << m_minimizeSteps << ")\n";
1079     }
1080   }
1081   if (getVelocityDistRandom(m_velocityDistRandom) == tr("True")) {
1082     scriptStream << "\nsimulation.context.setVelocitiesToTemperature("
1083                  << m_generationTemperature << "*unit.kelvin)\n";
1084   }
1085 
1086   // equilibrate
1087   if (m_equilibriationSteps > 0) {
1088     scriptStream << "print(\'Equilibrating...\')\n";
1089     scriptStream << "simulation.step(" << m_equilibriationSteps << ")\n\n";
1090   }
1091 
1092   // add reporters
1093   // if (d.simulation.dcd_reporter == 'True' &&
1094   // d.simulation.statedata_opts.length > 0) {
1095   if (m_DCDReporter) {
1096     scriptStream
1097       << "simulation.reporters.append(app.DCDReporter(\'trajectory.dcd\'";
1098     scriptStream << ", " << m_reportInterval << "))\n";
1099     scriptStream << "\n";
1100   }
1101   if (m_PDBReporter) {
1102     scriptStream
1103       << "simulation.reporters.append(app.PDBReporter(\'trajectory.pdb\'";
1104     scriptStream << ", " << m_reportInterval << "))\n";
1105     scriptStream << "\n";
1106   }
1107   if (m_stateDataReporter) {
1108     scriptStream << "simulation.reporters.append(app.StateDataReporter(";
1109     scriptStream << "stdout";
1110     scriptStream << ", " << m_reportInterval;
1111     if (m_stepIndex)
1112       scriptStream << ", step=True";
1113     if (m_time)
1114       scriptStream << ", time=True";
1115     if (m_potentialEnergy)
1116       scriptStream << ", potentialEnergy=True";
1117     if (m_kineticEnergy)
1118       scriptStream << ", kineticEnergy=True";
1119     if (m_totalEnergy)
1120       scriptStream << ", totalEnergy=True";
1121     if (m_temperatureCheck)
1122       scriptStream << ", temperature=True";
1123     if (m_volume)
1124       scriptStream << ", volume=True";
1125     if (m_density)
1126       scriptStream << ", density=True";
1127     if (m_progress)
1128       scriptStream << ", progress=True, remainingTime=True";
1129     if (m_speed)
1130       scriptStream << ", speed=True";
1131     // if using progress (which also implies remaining time), totalSteps
1132     // is required.
1133     if (m_progress)
1134       scriptStream << ", totalSteps=" << m_productionSteps;
1135     scriptStream << ", separator=\'\\t\'))\n";
1136     scriptStream << "\n";
1137   }
1138 
1139   // run
1140   scriptStream << "print(\'Running Production...\')\n";
1141   scriptStream << "simulation.step(" << m_productionSteps << ")\n";
1142   scriptStream << "print(\'Done!\')\n";
1143 
1144   return buffer;
1145 }
1146 
getForceFieldType(forceFieldType t)1147 QString OpenMMInputDialog::getForceFieldType(forceFieldType t)
1148 {
1149   // Translate the enum to text for the output generation
1150   switch (t) {
1151     case amber96:
1152       return "amber96";
1153     case amber99sb:
1154       return "amber99sb";
1155     case amber99sbildn:
1156       return "amber99sbildn";
1157     case amber99sbnmr:
1158       return "amber99sbnmr";
1159     case amber03:
1160       return "amber03";
1161     case amber10:
1162       return "amber10";
1163     default:
1164       return "amber99sbildn";
1165   }
1166 }
1167 
getImplicitSolventType(forceFieldType t)1168 QString OpenMMInputDialog::getImplicitSolventType(forceFieldType t)
1169 {
1170   // Translate the enum to text for the output generation
1171   switch (t) {
1172     case amber96:
1173       return "amber96_obc";
1174     case amber99sb:
1175       return "amber99_obc";
1176     case amber99sbildn:
1177       return "amber99_obc";
1178     case amber99sbnmr:
1179       return "amber99_obc";
1180     case amber03:
1181       return "amber03_obc";
1182     case amber10:
1183       return "amber10_obc";
1184     default:
1185       return "amber99_obc";
1186   }
1187 }
1188 
getConstraintType(constraintType t)1189 QString OpenMMInputDialog::getConstraintType(constraintType t)
1190 {
1191   switch (t) {
1192     case None:
1193       return "None";
1194     case HBonds:
1195       return "HBonds";
1196     case AllBonds:
1197       return "AllBonds";
1198     case HAngles:
1199       return "HAngles";
1200     default:
1201       return "HBonds";
1202   }
1203 }
1204 
getWaterModelType(waterModelType t)1205 QString OpenMMInputDialog::getWaterModelType(waterModelType t)
1206 {
1207   switch (t) {
1208     case spce:
1209       return "spce";
1210     case tip3p:
1211       return "tip3p";
1212     case tip4pew:
1213       return "tip4pew";
1214     case tip5p:
1215       return "tip5p";
1216     case implicit:
1217       return getImplicitSolventType(m_forceFieldType);
1218     default:
1219       return "tip3p";
1220   }
1221 }
1222 
getNonBondedType(nonBondedType t)1223 QString OpenMMInputDialog::getNonBondedType(nonBondedType t)
1224 {
1225   switch (t) {
1226     case NoCutoff:
1227       return "NoCutoff";
1228     case CutoffNonPeriodic:
1229       return "CutoffNonPeriodic";
1230     case CutoffPeriodic:
1231       return "CutoffPeriodic";
1232     case Ewald:
1233       return "Ewald";
1234     case PME:
1235       return "PME";
1236     default:
1237       return "PME";
1238   }
1239 }
1240 
getIntegratorType(integratorType t)1241 QString OpenMMInputDialog::getIntegratorType(integratorType t)
1242 {
1243   switch (t) {
1244     case Langevin:
1245       return "Langevin";
1246     case Verlet:
1247       return "Verlet";
1248     case Brownian:
1249       return "Brownian";
1250     case VariableVerlet:
1251       return "VariableVerlet";
1252     case VariableLangevin:
1253       return "VariableLangevin";
1254     default:
1255       return "Langevin";
1256   }
1257 }
1258 
getBarostatType(barostatType t)1259 QString OpenMMInputDialog::getBarostatType(barostatType t)
1260 {
1261   switch (t) {
1262     case NoBarostat:
1263       return "None";
1264     case MonteCarlo:
1265       return "MonteCarlo";
1266     default:
1267       return "None";
1268   }
1269 }
1270 
getRigidWater(int t)1271 QString OpenMMInputDialog::getRigidWater(int t)
1272 {
1273   switch (t) {
1274     case 0:
1275       return "True";
1276     case 1:
1277       return "False";
1278     default:
1279       return "False";
1280   }
1281 }
1282 
getVelocityDistRandom(int t)1283 QString OpenMMInputDialog::getVelocityDistRandom(int t)
1284 {
1285   switch (t) {
1286     case 0:
1287       return "True";
1288     case 1:
1289       return "False";
1290     default:
1291       return "True";
1292   }
1293 }
1294 
getPlatformType(platformType t)1295 QString OpenMMInputDialog::getPlatformType(platformType t)
1296 {
1297   switch (t) {
1298     case Reference:
1299       return "Reference";
1300     case OpenCL:
1301       return "OpenCL";
1302     case CUDA:
1303       return "CUDA";
1304     case CPU:
1305       return "CPU";
1306     default:
1307       return "CUDA";
1308   }
1309 }
1310 
getPrecisionType(precisionType t)1311 QString OpenMMInputDialog::getPrecisionType(precisionType t)
1312 {
1313   switch (t) {
1314     case singlePrecision:
1315       return "single";
1316     case mixedPrecision:
1317       return "mixed";
1318     case doublePrecision:
1319       return "double";
1320     default:
1321       return "mixed";
1322   }
1323 }
1324 
getMinimize(int t)1325 QString OpenMMInputDialog::getMinimize(int t)
1326 {
1327   switch (t) {
1328     case 0:
1329       return "True";
1330     case 1:
1331       return "False";
1332     default:
1333       return "True";
1334   }
1335 }
1336 
deckDirty(bool dirty)1337 void OpenMMInputDialog::deckDirty(bool dirty)
1338 {
1339   m_dirty = dirty;
1340   // ui.titleLine->setEnabled(!dirty);
1341   // ui.calculationCombo->setEnabled(!dirty);
1342   // ui.theoryCombo->setEnabled(!dirty);
1343   // ui.basisCombo->setEnabled(!dirty);
1344   // ui.multiplicitySpin->setEnabled(!dirty);
1345   // ui.chargeSpin->setEnabled(!dirty);
1346   ui.enableFormButton->setEnabled(dirty);
1347 }
1348 
readSettings(QSettings & settings)1349 void OpenMMInputDialog::readSettings(QSettings& settings)
1350 {
1351   m_savePath = settings.value("openmm/savepath").toString();
1352 }
1353 
writeSettings(QSettings & settings) const1354 void OpenMMInputDialog::writeSettings(QSettings& settings) const
1355 {
1356   settings.setValue("openmm/savepath", m_savePath);
1357 }
1358 
1359 } // namespace QtPlugins
1360 } // namespace Avogadro
1361