Skip to content

Commit

Permalink
Merge pull request #1897 from ghutchis/fixup-mo-window-bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
ghutchis authored Dec 28, 2024
2 parents 993d38d + b969f81 commit ad9f89a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 34 deletions.
41 changes: 26 additions & 15 deletions avogadro/core/basisset.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,28 +106,15 @@ class AVOGADROCORE_EXPORT BasisSet
virtual unsigned int molecularOrbitalCount(
ElectronType type = Paired) const = 0;

/**
* Check if the given MO number is the HOMO or not.
* @param n The MO number.
* @return True if the given MO number is the HOMO.
*/
bool homo(unsigned int n) { return n == homo(); }

/**
* @return The molecular orbital number corresponding to the HOMO orbital.
*/
unsigned int homo() const { return m_electrons[0] / 2; }
unsigned int homo(ElectronType type = Paired) const { return lumo(type) - 1; }

/**
* Check if the given MO number is the LUMO or not.
* @param n The MO number.
* @return True if the given MO number is the LUMO.
*/
bool lumo(unsigned int n) { return n == lumo(); }
/**
* @return The molecular orbital number corresponding to the LUMO orbital.
*/
unsigned int lumo() const { return m_electrons[0] / 2 + 1; }
unsigned int lumo(ElectronType type = Paired) const;

/**
* @return True of the basis set is valid, false otherwise.
Expand Down Expand Up @@ -244,6 +231,30 @@ class AVOGADROCORE_EXPORT BasisSet
std::vector<unsigned char> m_moOccupancy[2];
};

inline unsigned int BasisSet::lumo(ElectronType type) const
{
if (type == Beta) {
// check if we have occupancy data
if (m_moOccupancy[1].size() > 0) {
for (unsigned int i = 0; i < m_moOccupancy[1].size(); ++i) {
if (m_moOccupancy[1][i] == 0)
return i;
}
}
} else {
// alpha or paired
// check if we have occupancy data - more accurate
if (m_moOccupancy[0].size() > 0) {
for (unsigned int i = 0; i < m_moOccupancy[0].size(); ++i) {
if (m_moOccupancy[0][i] == 0)
return i;
}
}
}
// fall back to electron count
return m_electrons[0] / 2 + 1;
}

inline void BasisSet::setElectronCount(unsigned int n, ElectronType type)
{
switch (type) {
Expand Down
2 changes: 1 addition & 1 deletion avogadro/qtplugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ add_subdirectory(copypaste)
add_subdirectory(cp2kinput)
add_subdirectory(crystal)
add_subdirectory(customelements)
# add_subdirectory(dipole)
add_subdirectory(dipole)
add_subdirectory(editor)
add_subdirectory(fetchpdb)
add_subdirectory(focus)
Expand Down
41 changes: 38 additions & 3 deletions avogadro/qtplugins/surfaces/orbitals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,21 @@ Orbitals::Orbitals(QObject* p)
connect(m_action, SIGNAL(triggered()), SLOT(openDialog()));
}

Orbitals::~Orbitals() {}
Orbitals::~Orbitals()
{
// cancel the current running calculation
if (m_gaussianConcurrent) {
qDebug() << "Cancelling current calculation";
auto* watcher = &m_gaussianConcurrent->watcher();
if (watcher != nullptr && watcher->isRunning())
watcher->cancel();
}
delete m_runningMutex;

if (m_dialog)
m_dialog->deleteLater();
// molecule and basis are freed elsewhere
}

QList<QAction*> Orbitals::actions() const
{
Expand All @@ -61,6 +75,10 @@ void Orbitals::setMolecule(QtGui::Molecule* mol)
m_molecule = mol;
// check if it has basis set data
bool hasOrbitals = (m_molecule->basisSet() != nullptr);
// sanity check if there are actually mo coefficients
auto* basis = dynamic_cast<Core::GaussianSet*>(m_molecule->basisSet());
if (basis == nullptr || basis->moMatrix().size() == 0)
hasOrbitals = false;

if (hasOrbitals)
m_action->setEnabled(true);
Expand All @@ -76,6 +94,7 @@ void Orbitals::setMolecule(QtGui::Molecule* mol)
// Stuff we manage that will not be valid any longer
m_queue.clear();
m_currentRunningCalculation = -1;
m_currentMeshCalculation = -1;

if (m_basis) {
delete m_basis;
Expand All @@ -84,7 +103,7 @@ void Orbitals::setMolecule(QtGui::Molecule* mol)

loadBasis();

if (!m_basis || m_basis->electronCount() == 0)
if (!m_basis || m_basis->electronCount() == 0 || !hasOrbitals)
return; // no electrons, no orbitals

loadOrbitals();
Expand All @@ -103,6 +122,10 @@ void Orbitals::loadOrbitals()
if (m_basis == nullptr || m_molecule == nullptr)
return;

auto* basis = dynamic_cast<Core::GaussianSet*>(m_molecule->basisSet());
if (basis == nullptr || basis->moMatrix().size() == 0)
return;

if (!m_dialog) {
m_dialog = new OrbitalWidget(qobject_cast<QWidget*>(parent()), Qt::Window);
connect(m_dialog, SIGNAL(orbitalSelected(unsigned int)), this,
Expand All @@ -125,6 +148,11 @@ void Orbitals::moleculeChanged(unsigned int changes)
bool isEnabled = m_action->isEnabled();
bool hasOrbitals = (m_molecule->basisSet() != nullptr);

// sanity check if there are actually mo coefficients
auto* basis = dynamic_cast<Core::GaussianSet*>(m_molecule->basisSet());
if (basis == nullptr || basis->moMatrix().size() == 0)
hasOrbitals = false;

if (isEnabled != hasOrbitals) {
m_action->setEnabled(hasOrbitals);
if (hasOrbitals)
Expand Down Expand Up @@ -323,7 +351,9 @@ void Orbitals::calculateCube()
<< "\tOrbital " << cI->orbital << "\n"
<< "\tResolution " << cI->resolution;
#endif
m_currentMeshCalculation = m_currentRunningCalculation;
calculatePosMesh();
calculationComplete();
return;
}
}
Expand Down Expand Up @@ -466,10 +496,15 @@ void Orbitals::renderOrbital(unsigned int row)
// Find the most recent calc matching the selected orbital:
calcInfo calc;
int index = -1;
// in the event of ties, pick the best resolution
double resolution = OrbitalWidget::OrbitalQualityToDouble(0);
for (int i = 0; i < m_queue.size(); i++) {
calc = m_queue[i];
if (calc.orbital == orbital && calc.state == Completed) {
index = i;
if (calc.resolution <= resolution) {
resolution = calc.resolution;
index = i;
}
}
}

Expand Down
24 changes: 13 additions & 11 deletions avogadro/qtplugins/surfaces/orbitaltablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,20 @@ QVariant OrbitalTableModel::data(const QModelIndex& index, int role) const
return QString("%L1").arg(orb->energy, 0, 'f', 3);
case C_Status: {
// Check for divide by zero
int percent;
if (orb->max == orb->min)
return 0;
int percent =
100 * (orb->current - orb->min) / float(orb->max - orb->min);
// Adjust for stages
int stages = (orb->totalStages == 0) ? 1 : orb->totalStages;
percent /= float(stages);
percent += (orb->stage - 1) * (100.0 / float(stages));
// clamp to 100%
if (percent > 100)
percent = 100;
return QString("%L1 %").arg(percent);
percent = 0;
else {
percent = 100 * (orb->current - orb->min) / float(orb->max - orb->min);
// Adjust for stages
int stages = (orb->totalStages == 0) ? 1 : orb->totalStages;
percent /= float(stages);
percent += (orb->stage - 1) * (100.0 / float(stages));
// clamp to 100%
if (percent > 100)
percent = 100;
}
return QString("%L1%").arg(percent);
}
case C_Symmetry:
symbol = orb->symmetry;
Expand Down
3 changes: 2 additions & 1 deletion avogadro/qtplugins/surfaces/orbitalwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ OrbitalWidget::OrbitalWidget(QWidget* parent, Qt::WindowFlags f)
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
this, SLOT(tableClicked(const QItemSelection&)));
connect(ui.push_render, SIGNAL(clicked()), this, SLOT(renderClicked()));

// TODO: Implement configure dialog
ui.push_configure->setVisible(false);
connect(ui.push_configure, SIGNAL(clicked()), this, SLOT(configureClicked()));
Expand Down Expand Up @@ -171,7 +172,7 @@ void OrbitalWidget::renderClicked()
QModelIndex first = selection.first();
first = m_sortedTableModel->mapToSource(first);

int orbital = first.row() + 1;
int orbital = first.row(); // renderRequested handles the +1
emit renderRequested(orbital, quality);
}

Expand Down
6 changes: 3 additions & 3 deletions tests/core/basissettest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ TEST(BasisSetTest, homo)

basis.setElectronCount(2, BasisSet::Paired);
EXPECT_EQ(basis.homo(), 1);
EXPECT_TRUE(basis.homo(basis.homo()));
// EXPECT_TRUE(basis.homo(basis.homo()));

EXPECT_EQ(basis.lumo(), 2);
EXPECT_TRUE(basis.lumo(basis.lumo()));
// EXPECT_TRUE(basis.lumo(basis.lumo()));

basis = SlaterSet();
basis.setElectronCount(2, BasisSet::Alpha);
basis.setElectronCount(1, BasisSet::Beta);

EXPECT_EQ(basis.homo(), 1);
EXPECT_TRUE(basis.homo(basis.homo()));
// EXPECT_TRUE(basis.homo(basis.homo()));

// This is broken: the lumo could be either the
// next alpha or the next beta depending on the
Expand Down

0 comments on commit ad9f89a

Please sign in to comment.