Skip to content

Commit 32a35bb

Browse files
authored
Merge pull request #1479 from ghutchis/read-script-properties
Allow scripts to add properties (orbitals, vibrations, cubes)
2 parents 204a409 + 360dcee commit 32a35bb

File tree

9 files changed

+147
-25
lines changed

9 files changed

+147
-25
lines changed

avogadro/core/molecule.cpp

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
#include "color3f.h"
1010
#include "cube.h"
1111
#include "elements.h"
12+
#include "gaussianset.h"
1213
#include "layermanager.h"
1314
#include "mdlvalence_p.h"
1415
#include "mesh.h"
1516
#include "neighborperceiver.h"
1617
#include "residue.h"
18+
#include "slaterset.h"
1719
#include "unitcell.h"
1820

1921
#include <algorithm>
@@ -74,6 +76,54 @@ Molecule::Molecule(const Molecule& other)
7476
}
7577
}
7678

79+
void Molecule::readProperties(const Molecule& other)
80+
{
81+
m_label = other.m_label;
82+
m_colors = other.m_colors;
83+
// merge data maps by iterating through other's map
84+
for (auto it = other.m_data.constBegin(); it != other.m_data.constEnd(); ++it) {
85+
// even if we have the same key, we want to overwrite
86+
m_data.setValue(it->first, it->second);
87+
}
88+
// merge partial charge maps
89+
for (auto it = other.m_partialCharges.cbegin();
90+
it != other.m_partialCharges.cend(); ++it) {
91+
m_partialCharges[it->first] = it->second;
92+
}
93+
94+
// copy orbital information
95+
SlaterSet* slaterSet = dynamic_cast<SlaterSet*>(other.m_basisSet);
96+
if (slaterSet != nullptr) {
97+
m_basisSet = slaterSet->clone();
98+
m_basisSet->setMolecule(this);
99+
}
100+
GaussianSet* gaussianSet = dynamic_cast<GaussianSet*>(other.m_basisSet);
101+
if (gaussianSet != nullptr) {
102+
m_basisSet = gaussianSet->clone();
103+
m_basisSet->setMolecule(this);
104+
}
105+
106+
// copy over spectra information
107+
if (other.m_vibrationFrequencies.size() > 0) {
108+
m_vibrationFrequencies = other.m_vibrationFrequencies;
109+
m_vibrationIRIntensities = other.m_vibrationIRIntensities;
110+
m_vibrationRamanIntensities = other.m_vibrationRamanIntensities;
111+
m_vibrationLx = other.m_vibrationLx;
112+
}
113+
114+
// Copy over any meshes
115+
for (Index i = 0; i < other.meshCount(); ++i) {
116+
Mesh* m = addMesh();
117+
*m = *other.mesh(i);
118+
}
119+
120+
// Copy over any cubes
121+
for (Index i = 0; i < other.cubeCount(); ++i) {
122+
Cube* c = addCube();
123+
*c = *other.cube(i);
124+
}
125+
}
126+
77127
Molecule::Molecule(Molecule&& other) noexcept
78128
: m_data(other.m_data), m_partialCharges(std::move(other.m_partialCharges)),
79129
m_customElementMap(std::move(other.m_customElementMap)),
@@ -277,53 +327,52 @@ void Molecule::setFrozenAtom(Index atomId, bool frozen)
277327
return;
278328

279329
// check if we need to resize
280-
unsigned int size = m_frozenAtomMask.rows();
281-
if (m_frozenAtomMask.rows() != 3*m_atomicNumbers.size())
282-
m_frozenAtomMask.conservativeResize(3*m_atomicNumbers.size());
330+
unsigned int size = m_frozenAtomMask.rows();
331+
if (m_frozenAtomMask.rows() != 3 * m_atomicNumbers.size())
332+
m_frozenAtomMask.conservativeResize(3 * m_atomicNumbers.size());
283333

284334
// do we need to initialize new values?
285335
if (m_frozenAtomMask.rows() > size)
286336
for (unsigned int i = size; i < m_frozenAtomMask.rows(); ++i)
287337
m_frozenAtomMask[i] = 1.0;
288-
338+
289339
float value = frozen ? 0.0 : 1.0;
290340
if (atomId * 3 <= m_frozenAtomMask.rows() - 3) {
291-
m_frozenAtomMask[atomId*3] = value;
292-
m_frozenAtomMask[atomId*3+1] = value;
293-
m_frozenAtomMask[atomId*3+2] = value;
341+
m_frozenAtomMask[atomId * 3] = value;
342+
m_frozenAtomMask[atomId * 3 + 1] = value;
343+
m_frozenAtomMask[atomId * 3 + 2] = value;
294344
}
295345
}
296346

297347
bool Molecule::frozenAtom(Index atomId) const
298348
{
299349
bool frozen = false;
300350
if (atomId * 3 <= m_frozenAtomMask.rows() - 3) {
301-
frozen = (m_frozenAtomMask[atomId*3] == 0.0 &&
302-
m_frozenAtomMask[atomId*3+1] == 0.0 &&
303-
m_frozenAtomMask[atomId*3+2] == 0.0);
351+
frozen = (m_frozenAtomMask[atomId * 3] == 0.0 &&
352+
m_frozenAtomMask[atomId * 3 + 1] == 0.0 &&
353+
m_frozenAtomMask[atomId * 3 + 2] == 0.0);
304354
}
305355
return frozen;
306356
}
307357

308358
void Molecule::setFrozenAtomAxis(Index atomId, int axis, bool frozen)
309359
{
310360
// check if we need to resize
311-
unsigned int size = m_frozenAtomMask.rows();
312-
if (m_frozenAtomMask.rows() != 3*m_atomicNumbers.size())
313-
m_frozenAtomMask.conservativeResize(3*m_atomicNumbers.size());
361+
unsigned int size = m_frozenAtomMask.rows();
362+
if (m_frozenAtomMask.rows() != 3 * m_atomicNumbers.size())
363+
m_frozenAtomMask.conservativeResize(3 * m_atomicNumbers.size());
314364

315365
// do we need to initialize new values?
316366
if (m_frozenAtomMask.rows() > size)
317367
for (unsigned int i = size; i < m_frozenAtomMask.rows(); ++i)
318368
m_frozenAtomMask[i] = 1.0;
319-
369+
320370
float value = frozen ? 0.0 : 1.0;
321371
if (atomId * 3 <= m_frozenAtomMask.rows() - 3) {
322-
m_frozenAtomMask[atomId*3 + axis] = value;
372+
m_frozenAtomMask[atomId * 3 + axis] = value;
323373
}
324374
}
325375

326-
327376
void Molecule::setData(const std::string& name, const Variant& value)
328377
{
329378
m_data.setValue(name, value);

avogadro/core/molecule.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ class AVOGADROCORE_EXPORT Molecule
7373
/** Destroys the molecule object. */
7474
virtual ~Molecule();
7575

76+
/**
77+
* Adds the properties from the supplied
78+
* molecule to this molecule. Does not otherwise
79+
* modify atoms / bonds / residues, etc.
80+
*/
81+
void readProperties(const Molecule& other);
82+
7683
/** Sets the data value with @p name to @p value. */
7784
void setData(const std::string& name, const Variant& value);
7885

@@ -695,20 +702,20 @@ class AVOGADROCORE_EXPORT Molecule
695702

696703
/**
697704
* Freeze or unfreeze an atom for optimization
698-
*/
705+
*/
699706
void setFrozenAtom(Index atomId, bool frozen);
700707

701708
/**
702709
* Get the frozen status of an atom
703-
*/
710+
*/
704711
bool frozenAtom(Index atomId) const;
705712

706713
/**
707714
* Freeze or unfreeze X, Y, or Z coordinate of an atom for optimization
708715
* @param atomId The index of the atom to modify.
709716
* @param axis The axis to freeze (0, 1, or 2 for X, Y, or Z)
710717
* @param frozen True to freeze, false to unfreeze
711-
*/
718+
*/
712719
void setFrozenAtomAxis(Index atomId, int axis, bool frozen);
713720

714721
Eigen::VectorXd frozenAtomMask() const { return m_frozenAtomMask; }

avogadro/qtgui/interfacescript.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,11 @@ bool InterfaceScript::processCommand(Core::Molecule* mol)
252252
newMol.perceiveBondOrders();
253253
}
254254

255-
// just append some new bits
256-
if (obj["append"].toBool()) {
255+
// how do we handle this result?
256+
if (obj["readProperties"].toBool()) {
257+
guiMol->readProperties(newMol);
258+
guiMol->emitChanged(Molecule::Properties | Molecule::Added);
259+
} else if (obj["append"].toBool()) {
257260
guiMol->undoMolecule()->appendMolecule(newMol, m_displayName);
258261
} else { // replace the whole molecule
259262
Molecule::MoleculeChanges changes = (Molecule::Atoms | Molecule::Bonds |

avogadro/qtgui/molecule.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class AVOGADROQTGUI_EXPORT Molecule : public QObject, public Core::Molecule
7373
UnitCell = 0x04,
7474
Selection = 0x08,
7575
Layers = 0x16,
76+
Properties = 0x32,
7677
/** Operations that can affect the above types. */
7778
Added = 0x1024,
7879
Removed = 0x2048,
@@ -93,7 +94,8 @@ class AVOGADROQTGUI_EXPORT Molecule : public QObject, public Core::Molecule
9394
*/
9495
virtual AtomType addAtom(unsigned char atomicNumber, Index uniqueId);
9596

96-
AtomType addAtom(unsigned char number, Vector3 position3d, Index uniqueId = MaxIndex);
97+
AtomType addAtom(unsigned char number, Vector3 position3d,
98+
Index uniqueId = MaxIndex);
9799

98100
/**
99101
* @brief Remove the specified atom from the molecule.

avogadro/qtplugins/openbabel/obfileformat.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <QtCore/QCoreApplication>
1313
#include <QtCore/QDebug>
1414
#include <QtCore/QFileInfo>
15+
#include <QtCore/QTemporaryFile>
1516
#include <QtCore/QTimer>
1617

1718
using json = nlohmann::json;
@@ -73,7 +74,8 @@ OBFileFormat::OBFileFormat(const std::string& name_,
7374
m_identifier(identifier_), m_name(name_),
7475
m_specificationUrl(specificationUrl_), m_defaultFormat(defaultFormat_),
7576
m_fileOnly(fileOnly_)
76-
{}
77+
{
78+
}
7779

7880
OBFileFormat::~OBFileFormat() {}
7981

@@ -122,7 +124,6 @@ bool OBFileFormat::read(std::istream& in, Core::Molecule& molecule)
122124
// default is CML or CJSON
123125
QString format =
124126
QString::fromStdString(opts.value("format", m_defaultFormat));
125-
qDebug() << "Reading to format: " << format << m_defaultFormat.c_str();
126127

127128
if (!m_fileOnly) {
128129
// Determine length of data
@@ -149,6 +150,26 @@ bool OBFileFormat::read(std::istream& in, Core::Molecule& molecule)
149150
} else {
150151
// Can only read files. Need absolute path.
151152
QString filename = QString::fromStdString(fileName());
153+
if (filename.isEmpty()) {
154+
// no choice but to write to a temporary file
155+
in.seekg(0, std::ios_base::end);
156+
std::istream::pos_type length = in.tellg();
157+
in.seekg(0, std::ios_base::beg);
158+
in.clear();
159+
160+
// Extract data, hope it's not big
161+
QByteArray input;
162+
input.resize(static_cast<int>(length));
163+
in.read(input.data(), length);
164+
165+
QTemporaryFile tmpFile;
166+
tmpFile.setAutoRemove(false);
167+
tmpFile.open();
168+
tmpFile.write(input.data());
169+
tmpFile.close();
170+
filename = tmpFile.fileName();
171+
}
172+
152173
if (!QFileInfo(filename).isAbsolute()) {
153174
appendError("Internal error -- filename must be absolute! " +
154175
filename.toStdString());
@@ -281,6 +302,6 @@ Io::FileFormat* OBFileFormat::newInstance() const
281302
m_defaultFormat, m_fileOnly);
282303
}
283304

284-
} // namespace Avogadro
305+
} // namespace Avogadro::QtPlugins
285306

286307
#include "obfileformat.moc"

avogadro/qtplugins/spectra/spectra.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ QStringList Spectra::menuPath(QAction*) const
4545

4646
void Spectra::setMolecule(QtGui::Molecule* mol)
4747
{
48+
if (m_molecule != nullptr)
49+
m_molecule->disconnect(this);
50+
4851
bool isVibrational(false);
4952
if (mol->vibrationFrequencies().size())
5053
isVibrational = true;
@@ -56,6 +59,25 @@ void Spectra::setMolecule(QtGui::Molecule* mol)
5659

5760
if (isVibrational)
5861
openDialog();
62+
63+
connect(m_molecule, SIGNAL(changed(unsigned int)),
64+
SLOT(moleculeChanged(unsigned int)));
65+
}
66+
67+
void Spectra::moleculeChanged(unsigned int changes)
68+
{
69+
if (m_molecule == nullptr)
70+
return;
71+
72+
bool currentVibrational = m_actions[0]->isEnabled();
73+
bool isVibrational = (m_molecule->vibrationFrequencies().size() > 0);
74+
if (currentVibrational != isVibrational) {
75+
m_actions[0]->setEnabled(isVibrational);
76+
if (m_dialog)
77+
m_dialog->setMolecule(m_molecule); // update the dialog
78+
if (isVibrational)
79+
openDialog();
80+
}
5981
}
6082

6183
void Spectra::registerCommands()

avogadro/qtplugins/spectra/spectra.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public slots:
5353
void startVibrationAnimation();
5454
void stopVibrationAnimation();
5555
void openDialog();
56+
void moleculeChanged(unsigned int changes);
5657

5758
private slots:
5859
void advanceFrame();

avogadro/qtplugins/surfaces/surfaces.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ bool Surfaces::handleCommand(const QString& command, const QVariantMap& options)
224224

225225
void Surfaces::setMolecule(QtGui::Molecule* mol)
226226
{
227+
if (m_molecule != nullptr) {
228+
m_molecule->disconnect(this);
229+
}
230+
227231
if (mol->basisSet()) {
228232
m_basis = mol->basisSet();
229233
} else if (mol->cubes().size() != 0) {
@@ -234,6 +238,18 @@ void Surfaces::setMolecule(QtGui::Molecule* mol)
234238
m_mesh1 = nullptr;
235239
m_mesh2 = nullptr;
236240
m_molecule = mol;
241+
242+
if (m_molecule != nullptr) {
243+
connect(m_molecule, SIGNAL(changed(uint)), SLOT(moleculeChanged(uint)));
244+
}
245+
}
246+
247+
void Surfaces::moleculeChanged(unsigned int changes)
248+
{
249+
if (changes & Molecule::Added || changes & Molecule::Removed) {
250+
m_cubes = m_molecule->cubes();
251+
m_basis = m_molecule->basisSet();
252+
}
237253
}
238254

239255
QList<QAction*> Surfaces::actions() const

avogadro/qtplugins/surfaces/surfaces.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Surfaces : public QtGui::ExtensionPlugin
8585
public slots:
8686
bool handleCommand(const QString& command,
8787
const QVariantMap& options) override;
88+
void moleculeChanged(unsigned int changes);
8889

8990
private slots:
9091
void surfacesActivated();

0 commit comments

Comments
 (0)