From 31929547b1d1b1f0ed53e1146ad015e3f34e466c Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 20 Jan 2024 14:49:26 -0500 Subject: [PATCH 1/4] Add a "force" command, mostly for debugging Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/forcefield/forcefield.cpp | 72 +++++++++++++++--- avogadro/qtplugins/forcefield/forcefield.h | 1 + avogadro/qtplugins/forcefield/obmmenergy.cpp | 80 +++++++++++--------- 3 files changed, 109 insertions(+), 44 deletions(-) diff --git a/avogadro/qtplugins/forcefield/forcefield.cpp b/avogadro/qtplugins/forcefield/forcefield.cpp index 31c7095ee..d8d68a80c 100644 --- a/avogadro/qtplugins/forcefield/forcefield.cpp +++ b/avogadro/qtplugins/forcefield/forcefield.cpp @@ -49,6 +49,7 @@ const int configureAction = 2; const int freezeAction = 3; const int unfreezeAction = 4; const int constraintAction = 5; +const int forcesAction = 6; Forcefield::Forcefield(QObject* parent_) : ExtensionPlugin(parent_), m_method(nullptr) @@ -63,12 +64,12 @@ Forcefield::Forcefield(QObject* parent_) m_gradientTolerance = settings.value("gradientTolerance", 1.0e-4).toDouble(); settings.endGroup(); - refreshScripts(); - /* @todo - finish OBMM interface + // add the openbabel calculators first Calc::EnergyManager::registerModel(new OBMMEnergy("MMFF94")); Calc::EnergyManager::registerModel(new OBMMEnergy("UFF")); Calc::EnergyManager::registerModel(new OBMMEnergy("GAFF")); - */ + + refreshScripts(); QAction* action = new QAction(this); action->setEnabled(true); @@ -86,6 +87,14 @@ Forcefield::Forcefield(QObject* parent_) connect(action, SIGNAL(triggered()), SLOT(energy())); m_actions.push_back(action); + action = new QAction(this); + action->setEnabled(true); + action->setText(tr("Forces")); // calculate gradients + action->setData(forcesAction); + action->setProperty("menu priority", 910); + connect(action, SIGNAL(triggered()), SLOT(forces())); + m_actions.push_back(action); + action = new QAction(this); action->setEnabled(true); action->setText(tr("Configureā€¦")); @@ -295,6 +304,11 @@ void Forcefield::optimize() forces[i] = -0.1 * Vector3(gradient[3 * i], gradient[3 * i + 1], gradient[3 * i + 2]); } + } else { + // reset to last positions + positions = lastPositions; + gradient = Eigen::VectorXd::Zero(3 * n); + break; } // todo - merge these into one undo step @@ -307,18 +321,12 @@ void Forcefield::optimize() lastPositions = positions; // check for convergence - /* if (fabs(gradient.maxCoeff()) < m_gradientTolerance) break; if (fabs(currentEnergy - energy) < m_tolerance) break; - */ energy = currentEnergy; - } else { - // reset to last positions - positions = lastPositions; - gradient = Eigen::VectorXd::Zero(3 * n); } } @@ -345,6 +353,52 @@ void Forcefield::energy() QMessageBox::information(nullptr, tr("Avogadro"), msg); } +void Forcefield::forces() +{ + if (m_molecule == nullptr || m_method == nullptr) + return; + + int n = m_molecule->atomCount(); + + // double-check the mask + auto mask = m_molecule->frozenAtomMask(); + if (mask.rows() != 3 * n) { + mask = Eigen::VectorXd::Zero(3 * n); + // set to 1.0 + for (Index i = 0; i < 3 * n; ++i) { + mask[i] = 1.0; + } + } + m_method->setMolecule(m_molecule); + m_method->setMask(mask); + + // we have to cast the current 3d positions into a VectorXd + Core::Array pos = m_molecule->atomPositions3d(); + double* p = pos[0].data(); + Eigen::Map map(p, 3 * n); + Eigen::VectorXd positions = map; + + Eigen::VectorXd gradient = Eigen::VectorXd::Zero(3 * n); + // just to get the right size / shape + // we'll use this to draw the force arrows + Core::Array forces = m_molecule->atomPositions3d(); + + m_method->gradient(positions, gradient); + + for (size_t i = 0; i < n; ++i) { + forces[i] = + -0.1 * Vector3(gradient[3 * i], gradient[3 * i + 1], gradient[3 * i + 2]); + } + + m_molecule->setForceVectors(forces); + Molecule::MoleculeChanges changes = Molecule::Atoms | Molecule::Modified; + m_molecule->emitChanged(changes); + + QString msg( + tr("%1 Force Norm = %L2").arg(m_methodName.c_str()).arg(gradient.norm())); + QMessageBox::information(nullptr, tr("Avogadro"), msg); +} + std::string Forcefield::recommendedForceField() const { // if we have a unit cell, we need to use the LJ calculator diff --git a/avogadro/qtplugins/forcefield/forcefield.h b/avogadro/qtplugins/forcefield/forcefield.h index 05170b66c..a08e75675 100644 --- a/avogadro/qtplugins/forcefield/forcefield.h +++ b/avogadro/qtplugins/forcefield/forcefield.h @@ -71,6 +71,7 @@ public slots: private slots: void energy(); + void forces(); void optimize(); void freezeSelected(); void unfreezeSelected(); diff --git a/avogadro/qtplugins/forcefield/obmmenergy.cpp b/avogadro/qtplugins/forcefield/obmmenergy.cpp index e58d79824..837efa230 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.cpp +++ b/avogadro/qtplugins/forcefield/obmmenergy.cpp @@ -64,6 +64,7 @@ public slots: OBMMEnergy::OBMMEnergy(const std::string& method) : m_identifier(method), m_name(method), m_process(nullptr), + m_molecule(nullptr), #if defined(_WIN32) m_executable("obmm.exe") #else @@ -158,6 +159,8 @@ void OBMMEnergy::setupProcess() env.insert("BABEL_LIBDIR", QCoreApplication::applicationDirPath() + "/../lib/openbabel/" + dirs[0]); } else { + env.insert("BABEL_LIBDIR", QCoreApplication::applicationDirPath() + + "/../lib/openbabel/"); qDebug() << "Error, Open Babel plugins directory not found."; } #endif @@ -177,7 +180,7 @@ void OBMMEnergy::setMolecule(Core::Molecule* mol) // should check if the molecule is valid for this script // .. this should never happen, but let's be defensive - if (mol == nullptr) { + if (mol == nullptr || mol->atomCount() == 0) { return; // nothing to do } @@ -206,42 +209,43 @@ void OBMMEnergy::setMolecule(Core::Molecule* mol) // appendError("Error starting process."); return; } - ProcessListener listener(m_process); - QByteArray result; - if (!listener.waitForOutput(result)) { - // appendError("Error running process."); - return; - } - qDebug() << "OBMM start: " << result; + qDebug() << " state: " << m_process->state(); + + // ProcessListener listener(m_process); + QByteArray line, result; + result = m_process->readAllStandardOutput(); // okay, we need to write "load " to the interpreter // and then read the response - QByteArray input = "load " + m_tempFile.fileName().toLocal8Bit() + "\n"; + QByteArray input = "load " + m_tempFile.fileName().toLocal8Bit() + "\n\n"; m_process->write(input); - if (!listener.waitForOutput(result)) { - // appendError("Error running process."); - return; + bool ready = m_process->waitForReadyRead(); + result.clear(); + while (!result.contains("command >")) { + line = m_process->readLine(); + qDebug() << " read " << line; + result += line; } - qDebug() << "OBMM: " << result; + m_process->readAllStandardOutput(); - // set the method m_identifier.c_str() + - input = QByteArray("ff MMFF94\n"); + input = "\n"; m_process->write(input); - if (!listener.waitForOutput(result)) { - // appendError("Error running process."); - return; - } - qDebug() << "OBMM ff: " << result; - - // check for an energy - input = QByteArray("energy\n"); + ready = m_process->waitForReadyRead(); result.clear(); + result = m_process->readAllStandardOutput(); + qDebug() << "OBMM: " << result; + + // set the method m_identifier.c_str() + + qDebug() << " setting force field"; + input = QByteArray("ff UFF\n\n"); m_process->write(input); + ready = m_process->waitForReadyRead(); result.clear(); while (!result.contains("command >")) { result += m_process->readLine(); } - qDebug() << "OBMM energy: " << result; + result += m_process->readAllStandardOutput(); + qDebug() << "OBMM ff: " << result; } Real OBMMEnergy::value(const Eigen::VectorXd& x) @@ -249,21 +253,23 @@ Real OBMMEnergy::value(const Eigen::VectorXd& x) if (m_molecule == nullptr || m_process == nullptr) return 0.0; // nothing to do + QByteArray input = "\n"; m_process->waitForReadyRead(); QByteArray result; while (!result.contains("command >")) { result += m_process->readLine(); } + result += m_process->readAllStandardOutput(); qDebug() << " starting " << result; // write the new coordinates and read the energy - QByteArray input = "coord\n"; + input = "coord\n"; for (Index i = 0; i < x.size(); i += 3) { // write as x y z (space separated) input += QString::number(x[i]) + " " + QString::number(x[i + 1]) + " " + QString::number(x[i + 2]) + "\n"; } - input += "\n"; + input += "\n\n"; m_process->write(input); m_process->waitForReadyRead(); @@ -271,17 +277,20 @@ Real OBMMEnergy::value(const Eigen::VectorXd& x) while (!result.contains("command >")) { result += m_process->readLine(); } + result += m_process->readAllStandardOutput(); qDebug() << " asking energy " << result << m_process->state(); // now ask for the energy - input = "energy\n\n"; - result.clear(); + input = "energy\n\n\n"; m_process->write(input); m_process->waitForReadyRead(); + qDebug() << " waiting for read "; + result.clear(); while (!result.contains("command >")) { result += m_process->readLine(); } + result += m_process->readAllStandardOutput(); qDebug() << "OBMM: " << result; @@ -307,13 +316,10 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) if (m_molecule == nullptr || m_process == nullptr) return; - EnergyCalculator::gradient(x, grad); - return; - qDebug() << "OBMM: gradient"; // write the new coordinates and read the energy - QByteArray input = "coord\n"; + QByteArray input = "coord\n\n"; for (Index i = 0; i < x.size(); i += 3) { // write as x y z (space separated) input += QString::number(x[i]) + " " + QString::number(x[i + 1]) + " " + @@ -322,8 +328,8 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) m_process->write(input); qDebug() << "OBMM Grad wrote coords"; - m_process->waitForReadyRead(); QByteArray result; + m_process->waitForReadyRead(); while (m_process->canReadLine()) { result += m_process->readLine(); } @@ -331,14 +337,14 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) qDebug() << "OBMM: " << result; // now ask for the energy - input = "grad\n"; + input = "grad\n\n"; m_process->write(input); m_process->waitForReadyRead(); while (m_process->canReadLine()) { result += m_process->readLine(); } - qDebug() << "OBMM: " << result; + qDebug() << "OBMM: grad: " << result; // go through lines in result until we see "gradient " QStringList lines = QString(result).remove('\r').split('\n'); @@ -347,6 +353,7 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) for (auto line : lines) { if (line.contains("gradient")) { readingGradient = true; + qDebug() << " Got a gradient "; continue; } if (readingGradient) { @@ -360,6 +367,9 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) } } + qDebug() << " grad norm: " << grad.norm(); + grad *= -1; // OpenBabel outputs forces, not grads + cleanGradients(grad); } From eb7b180673b09111c6b079f0ebc5c5964f9349db Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 2 Feb 2024 01:31:09 -0500 Subject: [PATCH 2/4] Working obmm interface using wait for now Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/forcefield/obmmenergy.cpp | 136 +++++++------------ avogadro/qtplugins/forcefield/obmmenergy.h | 1 + 2 files changed, 52 insertions(+), 85 deletions(-) diff --git a/avogadro/qtplugins/forcefield/obmmenergy.cpp b/avogadro/qtplugins/forcefield/obmmenergy.cpp index 837efa230..9501d4086 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.cpp +++ b/avogadro/qtplugins/forcefield/obmmenergy.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace Avogadro::QtPlugins { @@ -118,6 +119,34 @@ OBMMEnergy::~OBMMEnergy() delete m_process; } +QByteArray OBMMEnergy::writeAndRead(const QByteArray& input) +{ + if (m_process == nullptr) + return QByteArray(); + + QByteArray result, line; + m_process->write(input + "\n"); + QThread::msleep(1); + m_process->waitForReadyRead(500); + bool gotInvalid = false; + while (m_process->canReadLine() && !line.startsWith("command >")) { + line = m_process->readLine(); + result += line; + } + // check if we've really flushed the output + if (!result.contains("invalid command\n command >")) { + m_process->write(" \n"); + QThread::msleep(1); + m_process->waitForReadyRead(500); + while (m_process->canReadLine()) { + line = m_process->readLine(); + result += line; + } + } + result += m_process->readAllStandardOutput(); + return result; +} + void OBMMEnergy::setupProcess() { if (m_process != nullptr) { @@ -207,45 +236,28 @@ void OBMMEnergy::setMolecule(Core::Molecule* mol) m_process->start(m_executable, QStringList() << m_tempFile.fileName()); if (!m_process->waitForStarted()) { // appendError("Error starting process."); + qDebug() << "OBMM: Error starting process."; return; } - qDebug() << " state: " << m_process->state(); - - // ProcessListener listener(m_process); - QByteArray line, result; - result = m_process->readAllStandardOutput(); - // okay, we need to write "load " to the interpreter - // and then read the response - QByteArray input = "load " + m_tempFile.fileName().toLocal8Bit() + "\n\n"; - m_process->write(input); + QByteArray input, line, result; bool ready = m_process->waitForReadyRead(); result.clear(); - while (!result.contains("command >")) { - line = m_process->readLine(); - qDebug() << " read " << line; - result += line; - } - m_process->readAllStandardOutput(); - - input = "\n"; - m_process->write(input); - ready = m_process->waitForReadyRead(); - result.clear(); - result = m_process->readAllStandardOutput(); - qDebug() << "OBMM: " << result; - - // set the method m_identifier.c_str() + - qDebug() << " setting force field"; - input = QByteArray("ff UFF\n\n"); - m_process->write(input); - ready = m_process->waitForReadyRead(); - result.clear(); while (!result.contains("command >")) { result += m_process->readLine(); + if (!m_process->canReadLine()) + break; } result += m_process->readAllStandardOutput(); - qDebug() << "OBMM ff: " << result; + + // set the method m_identifier.c_str() + + input = QByteArray("ff ") + m_identifier.c_str(); + result = writeAndRead(input); + + // okay, we need to write "load " to the interpreter + // and then read the response + input = "load " + m_tempFile.fileName().toLocal8Bit(); + result = writeAndRead(input); } Real OBMMEnergy::value(const Eigen::VectorXd& x) @@ -253,14 +265,7 @@ Real OBMMEnergy::value(const Eigen::VectorXd& x) if (m_molecule == nullptr || m_process == nullptr) return 0.0; // nothing to do - QByteArray input = "\n"; - m_process->waitForReadyRead(); - QByteArray result; - while (!result.contains("command >")) { - result += m_process->readLine(); - } - result += m_process->readAllStandardOutput(); - qDebug() << " starting " << result; + QByteArray input, result; // write the new coordinates and read the energy input = "coord\n"; @@ -269,45 +274,24 @@ Real OBMMEnergy::value(const Eigen::VectorXd& x) input += QString::number(x[i]) + " " + QString::number(x[i + 1]) + " " + QString::number(x[i + 2]) + "\n"; } - input += "\n\n"; - m_process->write(input); - m_process->waitForReadyRead(); - result.clear(); - while (!result.contains("command >")) { - result += m_process->readLine(); - } - result += m_process->readAllStandardOutput(); - - qDebug() << " asking energy " << result << m_process->state(); + result = writeAndRead(input); // now ask for the energy - input = "energy\n\n\n"; - m_process->write(input); - m_process->waitForReadyRead(); - qDebug() << " waiting for read "; - result.clear(); - while (!result.contains("command >")) { - result += m_process->readLine(); - } - result += m_process->readAllStandardOutput(); - - qDebug() << "OBMM: " << result; + input = "energy\n"; + result = writeAndRead(input); // go through lines in result until we see "total energy" QStringList lines = QString(result).remove('\r').split('\n'); double energy = 0.0; for (auto line : lines) { if (line.contains("total energy =")) { - qDebug() << " OBMM: " << line; QStringList items = line.split(" ", Qt::SkipEmptyParts); if (items.size() > 4) energy = items[3].toDouble(); } } - qDebug() << " OBMM: " << energy << " done"; - return energy; // if conversion fails, returns 0.0 } @@ -316,35 +300,19 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) if (m_molecule == nullptr || m_process == nullptr) return; - qDebug() << "OBMM: gradient"; - // write the new coordinates and read the energy - QByteArray input = "coord\n\n"; + QByteArray result, input = "coord\n"; for (Index i = 0; i < x.size(); i += 3) { // write as x y z (space separated) input += QString::number(x[i]) + " " + QString::number(x[i + 1]) + " " + QString::number(x[i + 2]) + "\n"; } - m_process->write(input); - qDebug() << "OBMM Grad wrote coords"; - QByteArray result; - m_process->waitForReadyRead(); - while (m_process->canReadLine()) { - result += m_process->readLine(); - } - - qDebug() << "OBMM: " << result; + result = writeAndRead(input); // now ask for the energy - input = "grad\n\n"; - m_process->write(input); - m_process->waitForReadyRead(); - while (m_process->canReadLine()) { - result += m_process->readLine(); - } - - qDebug() << "OBMM: grad: " << result; + input = "grad"; + result = writeAndRead(input); // go through lines in result until we see "gradient " QStringList lines = QString(result).remove('\r').split('\n'); @@ -353,13 +321,12 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) for (auto line : lines) { if (line.contains("gradient")) { readingGradient = true; - qDebug() << " Got a gradient "; continue; } if (readingGradient) { QStringList items = line.split(" ", Qt::SkipEmptyParts); if (items.size() == 3) { - grad[3 * i] = -1.0 * items[0].toDouble(); + grad[3 * i] = items[0].toDouble(); grad[3 * i + 1] = items[1].toDouble(); grad[3 * i + 2] = items[2].toDouble(); ++i; @@ -367,7 +334,6 @@ void OBMMEnergy::gradient(const Eigen::VectorXd& x, Eigen::VectorXd& grad) } } - qDebug() << " grad norm: " << grad.norm(); grad *= -1; // OpenBabel outputs forces, not grads cleanGradients(grad); diff --git a/avogadro/qtplugins/forcefield/obmmenergy.h b/avogadro/qtplugins/forcefield/obmmenergy.h index f12e7ba1f..49a269468 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.h +++ b/avogadro/qtplugins/forcefield/obmmenergy.h @@ -74,6 +74,7 @@ class OBMMEnergy : public Avogadro::Calc::EnergyCalculator * @brief Synchronous use of the QProcess. */ class ProcessListener; + QByteArray writeAndRead(const QByteArray& input); private: Core::Molecule* m_molecule; From 5631f0ded224e882eaf42dc606ed481b924261bb Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 2 Feb 2024 09:53:08 -0500 Subject: [PATCH 3/4] Decrease latency Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/forcefield/forcefield.cpp | 4 ++-- avogadro/qtplugins/forcefield/obmmenergy.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/avogadro/qtplugins/forcefield/forcefield.cpp b/avogadro/qtplugins/forcefield/forcefield.cpp index d8d68a80c..b85de0f5a 100644 --- a/avogadro/qtplugins/forcefield/forcefield.cpp +++ b/avogadro/qtplugins/forcefield/forcefield.cpp @@ -64,7 +64,7 @@ Forcefield::Forcefield(QObject* parent_) m_gradientTolerance = settings.value("gradientTolerance", 1.0e-4).toDouble(); settings.endGroup(); - // add the openbabel calculators first + // add the openbabel calculators in case they don't exist Calc::EnergyManager::registerModel(new OBMMEnergy("MMFF94")); Calc::EnergyManager::registerModel(new OBMMEnergy("UFF")); Calc::EnergyManager::registerModel(new OBMMEnergy("GAFF")); @@ -261,7 +261,7 @@ void Forcefield::optimize() cppoptlib::Criteria crit = cppoptlib::Criteria::defaults(); // e.g., every N steps, update coordinates - crit.iterations = 5; + crit.iterations = 2; // we don't set function or gradient criteria // .. these seem to be broken in the solver code // .. so we handle ourselves diff --git a/avogadro/qtplugins/forcefield/obmmenergy.cpp b/avogadro/qtplugins/forcefield/obmmenergy.cpp index 9501d4086..a5f9ee57e 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.cpp +++ b/avogadro/qtplugins/forcefield/obmmenergy.cpp @@ -127,7 +127,7 @@ QByteArray OBMMEnergy::writeAndRead(const QByteArray& input) QByteArray result, line; m_process->write(input + "\n"); QThread::msleep(1); - m_process->waitForReadyRead(500); + m_process->waitForReadyRead(50); bool gotInvalid = false; while (m_process->canReadLine() && !line.startsWith("command >")) { line = m_process->readLine(); @@ -137,7 +137,7 @@ QByteArray OBMMEnergy::writeAndRead(const QByteArray& input) if (!result.contains("invalid command\n command >")) { m_process->write(" \n"); QThread::msleep(1); - m_process->waitForReadyRead(500); + m_process->waitForReadyRead(50); while (m_process->canReadLine()) { line = m_process->readLine(); result += line; From d095e6bbf94409fe074514097a77ec53186e1f44 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Fri, 2 Feb 2024 12:44:03 -0500 Subject: [PATCH 4/4] Some cleanups of unused code Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/forcefield/forcefield.cpp | 10 ++-- avogadro/qtplugins/forcefield/obmmenergy.cpp | 53 ++------------------ avogadro/qtplugins/forcefield/obmmenergy.h | 5 -- 3 files changed, 8 insertions(+), 60 deletions(-) diff --git a/avogadro/qtplugins/forcefield/forcefield.cpp b/avogadro/qtplugins/forcefield/forcefield.cpp index b85de0f5a..285a9e292 100644 --- a/avogadro/qtplugins/forcefield/forcefield.cpp +++ b/avogadro/qtplugins/forcefield/forcefield.cpp @@ -31,9 +31,6 @@ #include #include -#include -#include -#include #include namespace Avogadro { @@ -132,7 +129,11 @@ QList Forcefield::actions() const QStringList Forcefield::menuPath(QAction* action) const { QStringList path; - path << tr("&Extensions") << tr("&Calculate"); + if (action->data().toInt() == optimizeAction) + path << tr("&Extensions"); + else + path << tr("&Extensions") << tr("&Calculate"); + return path; } @@ -229,7 +230,6 @@ void Forcefield::optimize() m_molecule->undoMolecule()->setInteractive(true); cppoptlib::LbfgsSolver solver; - // cppoptlib::ConjugatedGradientDescentSolver solver; int n = m_molecule->atomCount(); diff --git a/avogadro/qtplugins/forcefield/obmmenergy.cpp b/avogadro/qtplugins/forcefield/obmmenergy.cpp index a5f9ee57e..594dba9f8 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.cpp +++ b/avogadro/qtplugins/forcefield/obmmenergy.cpp @@ -17,52 +17,6 @@ namespace Avogadro::QtPlugins { -class OBMMEnergy::ProcessListener : public QObject -{ - Q_OBJECT -public: - ProcessListener(QProcess* proc) - : QObject(), m_finished(false), m_process(proc) - { - } - - bool waitForOutput(QByteArray output, int msTimeout = 2000) - { - connect(m_process, SIGNAL(readyRead()), SLOT(readyRead())); - if (!wait(msTimeout)) - return false; - - // success! - output = m_output; - disconnect(m_process, nullptr, nullptr, nullptr); - m_finished = false; - return true; - } - -public slots: - void readyRead() - { - m_finished = true; - m_output = m_process->readAllStandardOutput(); - } - -private: - bool wait(int msTimeout) - { - QTimer timer; - timer.start(msTimeout); - - while (timer.isActive() && !m_finished) - qApp->processEvents(QEventLoop::AllEvents, 500); - - return m_finished; - } - - QProcess* m_process; - bool m_finished; - QByteArray m_output; -}; - OBMMEnergy::OBMMEnergy(const std::string& method) : m_identifier(method), m_name(method), m_process(nullptr), m_molecule(nullptr), @@ -127,8 +81,7 @@ QByteArray OBMMEnergy::writeAndRead(const QByteArray& input) QByteArray result, line; m_process->write(input + "\n"); QThread::msleep(1); - m_process->waitForReadyRead(50); - bool gotInvalid = false; + m_process->waitForReadyRead(5); while (m_process->canReadLine() && !line.startsWith("command >")) { line = m_process->readLine(); result += line; @@ -137,7 +90,7 @@ QByteArray OBMMEnergy::writeAndRead(const QByteArray& input) if (!result.contains("invalid command\n command >")) { m_process->write(" \n"); QThread::msleep(1); - m_process->waitForReadyRead(50); + m_process->waitForReadyRead(5); while (m_process->canReadLine()) { line = m_process->readLine(); result += line; @@ -241,7 +194,7 @@ void OBMMEnergy::setMolecule(Core::Molecule* mol) } QByteArray input, line, result; - bool ready = m_process->waitForReadyRead(); + m_process->waitForReadyRead(); result.clear(); while (!result.contains("command >")) { result += m_process->readLine(); diff --git a/avogadro/qtplugins/forcefield/obmmenergy.h b/avogadro/qtplugins/forcefield/obmmenergy.h index 49a269468..63d0d9d2b 100644 --- a/avogadro/qtplugins/forcefield/obmmenergy.h +++ b/avogadro/qtplugins/forcefield/obmmenergy.h @@ -23,10 +23,6 @@ namespace Io { class FileFormat; } -namespace QtGui { -class PythonScript; -} - namespace QtPlugins { class OBMMEnergy : public Avogadro::Calc::EnergyCalculator @@ -73,7 +69,6 @@ class OBMMEnergy : public Avogadro::Calc::EnergyCalculator /** * @brief Synchronous use of the QProcess. */ - class ProcessListener; QByteArray writeAndRead(const QByteArray& input); private: