Skip to content

Commit

Permalink
Add an initial conformer property window
Browse files Browse the repository at this point in the history
Signed-off-by: Geoff Hutchison <geoff.hutchison@gmail.com>
  • Loading branch information
ghutchis committed Dec 3, 2024
1 parent ca9fa20 commit 7682af5
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 19 deletions.
82 changes: 72 additions & 10 deletions avogadro/qtplugins/propertytables/propertymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "propertymodel.h"

#include <avogadro/calc/chargemanager.h>
#include <avogadro/core/array.h>
#include <avogadro/core/atom.h>
#include <avogadro/core/bond.h>
#include <avogadro/core/elements.h>
Expand All @@ -25,6 +26,7 @@

namespace Avogadro {

using Avogadro::Core::Array;
using Avogadro::QtGui::Molecule;
using QtGui::Molecule;
using QtGui::RWAtom;
Expand All @@ -45,8 +47,23 @@ const int AngleColumns = 5;
const int TorsionColumns = 6;
// name, number, chain, secondary structure, heterogen, color
const int ResidueColumns = 6;
// number, energy, ??
const int ConformerColumns = 2;
// number, rmsd, energy or more depending on available properties
const int ConformerColumns = 1;

// compute the RMSD between the two sets of coordinates
inline double calcRMSD(const Array<Vector3>& v1, const Array<Vector3>& v2)
{
// if they're not the same length, it's an error
if (v1.size() != v2.size())
return numeric_limits<double>::quiet_NaN();

double sum = 0.0;
for (size_t i = 0; i < v1.size(); ++i) {
Vector3 diff = v1[i] - v2[i];
sum += diff.squaredNorm();
}
return sqrt(sum / v1.size());
}

inline double distance(Vector3 v1, Vector3 v2)
{
Expand Down Expand Up @@ -119,8 +136,12 @@ int PropertyModel::columnCount(const QModelIndex& parent) const
return TorsionColumns;
case ResidueType:
return ResidueColumns;
case ConformerType:
return ConformerColumns;
case ConformerType: {
if (m_molecule->hasData("energies"))
return ConformerColumns + 1;
else
return ConformerColumns;
}
default:
return 0;
}
Expand Down Expand Up @@ -204,6 +225,9 @@ QVariant PropertyModel::data(const QModelIndex& index, int role) const
return toVariant(Qt::AlignHCenter | Qt::AlignVCenter);
} else if (m_type == ResidueType) {
return toVariant(Qt::AlignHCenter | Qt::AlignVCenter);
} else if (m_type == ConformerType) {
return toVariant(Qt::AlignRight |
Qt::AlignVCenter); // RMSD or other properties
}
}

Expand All @@ -227,9 +251,6 @@ QVariant PropertyModel::data(const QModelIndex& index, int role) const
if (role != Qt::UserRole && role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();

// if (!m_validCache)
// updateCache();

if (m_type == AtomType) {
auto column = static_cast<AtomColumn>(index.column());

Expand Down Expand Up @@ -288,7 +309,7 @@ QVariant PropertyModel::data(const QModelIndex& index, int role) const
case BondDataOrder:
return bond.order();
default: // length, rounded to 4 decimals
return QString("%L1").arg(
return QString("%L1 Å").arg(
distance(atom1.position3d(), atom2.position3d()), 0, 'f', 3);
}
} else if (m_type == ResidueType) {
Expand Down Expand Up @@ -342,7 +363,7 @@ QVariant PropertyModel::data(const QModelIndex& index, int role) const
case AngleDataAtom3:
return QVariant::fromValue(std::get<2>(angle) + 1);
case AngleDataValue:
return QString("%L1").arg(calcAngle(a1, a2, a3), 0, 'f', 3);
return QString("%L1 °").arg(calcAngle(a1, a2, a3), 0, 'f', 3);
default:
return QVariant();
}
Expand Down Expand Up @@ -378,10 +399,37 @@ QVariant PropertyModel::data(const QModelIndex& index, int role) const
case TorsionDataAtom4:
return QVariant::fromValue(std::get<3>(torsion) + 1);
case TorsionDataValue:
return QString("%L1").arg(calcDihedral(a1, a2, a3, a4), 0, 'f', 3);
return QString("%L1 °").arg(calcDihedral(a1, a2, a3, a4), 0, 'f', 3);
default:
return QVariant();
}
} else if (m_type == ConformerType) {
auto column = static_cast<ConformerColumn>(index.column());
if (row >= static_cast<int>(m_molecule->coordinate3dCount()) ||
column > ConformerColumns) {
return QVariant(); // invalid index
}

switch (column) {
case ConformerDataRMSD: { // rmsd
double rmsd = 0.0;
if (row > 0) {
rmsd = calcRMSD(m_molecule->coordinate3d(row),
m_molecule->coordinate3d(0));
}

return QString("%L1 Å").arg(rmsd, 0, 'f', 3);
}
case ConformerDataEnergy: {
double energy = 0.0;
if (m_molecule->hasData("energies")) {
auto energies = m_molecule->data("energies").toList();
if (row < static_cast<int>(energies.size()))
energy = energies[row];
}
return QString("%L1").arg(energy, 0, 'f', 4);
}
}
}

return QVariant();
Expand Down Expand Up @@ -500,6 +548,20 @@ QVariant PropertyModel::headerData(int section, Qt::Orientation orientation,
}
} else // row headers
return QString("%L1").arg(section + 1);
} else if (m_type == ConformerType) {
// check if we have energies
bool hasEnergies = (m_molecule->hasData("energies"));
if (orientation == Qt::Horizontal) {
unsigned int column = static_cast<ConformerColumn>(section);
switch (column) {
case ConformerDataRMSD:
return tr("RMSD (Å)", "root mean squared displacement in Angstrom");
case ConformerDataEnergy:
// should only hit this if we have energies anyway
return hasEnergies ? tr("Energy") : tr("Property");
}
} else // row headers
return QString("%L1").arg(section + 1);
}

return QVariant();
Expand Down
5 changes: 2 additions & 3 deletions avogadro/qtplugins/propertytables/propertymodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ public slots:
std::vector<int> m_fragment;
Eigen::Affine3d m_transform;
bool fragmentHasAtom(int uid) const;
void buildFragment(const QtGui::RWBond& bond,
const QtGui::RWAtom& startAtom);
void buildFragment(const QtGui::RWBond& bond, const QtGui::RWAtom& startAtom);
bool fragmentRecurse(const QtGui::RWBond& bond,
const QtGui::RWAtom& startAtom,
const QtGui::RWAtom& currentAtom);
Expand Down Expand Up @@ -152,7 +151,7 @@ public slots:
// Conformer Data
enum ConformerColumn
{
ConformerDataType = 0,
ConformerDataRMSD = 0,
ConformerDataEnergy
};

Expand Down
27 changes: 21 additions & 6 deletions avogadro/qtplugins/propertytables/propertytables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ PropertyTables::PropertyTables(QObject* parent_)
action->setEnabled(false); // changed by molecule
connect(action, SIGNAL(triggered()), SLOT(showDialog()));
m_actions.append(action);

action = new QAction(this);
action->setText(tr("Conformer Properties…"));
action->setData(PropertyType::ConformerType);
action->setProperty("menu priority", 830);
action->setEnabled(false); // changed by molecule
connect(action, SIGNAL(triggered()), SLOT(showDialog()));
m_actions.append(action);
}

PropertyTables::~PropertyTables() {}
Expand Down Expand Up @@ -86,11 +94,14 @@ void PropertyTables::setMolecule(QtGui::Molecule* mol)
m_molecule = mol;

// check if there are residues
if (m_molecule->residueCount() > 0) {
for (const auto& action : m_actions) {
if (action->data().toInt() == PropertyType::ResidueType)
action->setEnabled(true);
}
bool haveResidues = (m_molecule->residueCount() > 0);
// technically coordinate sets
bool haveConformers = (m_molecule->coordinate3dCount() > 1);
for (const auto& action : m_actions) {
if (action->data().toInt() == PropertyType::ResidueType)
action->setEnabled(haveResidues);
else if (action->data().toInt() == PropertyType::ConformerType)
action->setEnabled(haveConformers);
}
}

Expand All @@ -104,6 +115,10 @@ void PropertyTables::showDialog()
m_molecule->residueCount() == 0)
return;

if (action->data().toInt() == PropertyType::ConformerType &&
m_molecule->coordinate3dCount() < 2)
return;

auto* dialog = new QDialog(qobject_cast<QWidget*>(parent()));
auto* layout = new QVBoxLayout(dialog);
dialog->setLayout(layout);
Expand Down Expand Up @@ -149,4 +164,4 @@ void PropertyTables::showDialog()
dialog->show();
}

} // namespace Avogadro
} // namespace Avogadro::QtPlugins
14 changes: 14 additions & 0 deletions avogadro/qtplugins/propertytables/propertyview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "propertyview.h"

#include <avogadro/core/residue.h>
#include <avogadro/qtgui/molecule.h>

#include <QAction>
Expand Down Expand Up @@ -137,6 +138,19 @@ void PropertyView::selectionChanged(const QItemSelection& selected,
m_molecule->undoMolecule()->setAtomSelected(std::get<2>(torsion), true);
m_molecule->undoMolecule()->setAtomSelected(std::get<3>(torsion), true);
}
} else if (m_type == PropertyType::ResidueType) {
// select all the atoms in the residue
if (m_model != nullptr) {
const auto residue = m_molecule->residue(rowNum);
auto atoms = residue.residueAtoms();
for (Index i = 0; i < atoms.size(); ++i) {
const auto atom = atoms[i];
m_molecule->undoMolecule()->setAtomSelected(atom.index(), true);
}
}
} else if (m_type == PropertyType::ConformerType) {
// selecting a row means switching to that conformer
m_molecule->setCoordinate3d(rowNum);
}
} // end loop through selected

Expand Down

0 comments on commit 7682af5

Please sign in to comment.