Skip to content

Commit

Permalink
Merge pull request #1495 from ghutchis/add-bond-labels
Browse files Browse the repository at this point in the history
Adding support for bond label in base classes and CJSON
  • Loading branch information
ghutchis authored Dec 23, 2023
2 parents b45dcfd + e3f4078 commit 762a0cb
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 69 deletions.
4 changes: 2 additions & 2 deletions avogadro/core/atom.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,13 @@ Vector3 AtomTemplate<Molecule_T>::forceVector() const
template <class Molecule_T>
void AtomTemplate<Molecule_T>::setLabel(const std::string& label)
{
m_molecule->setLabel(m_index, label);
m_molecule->setAtomLabel(m_index, label);
}

template <class Molecule_T>
std::string AtomTemplate<Molecule_T>::label() const
{
return m_molecule->label(m_index);
return m_molecule->atomLabel(m_index);
}

} // namespace Core
Expand Down
24 changes: 14 additions & 10 deletions avogadro/core/molecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ Molecule::Molecule(const Molecule& other)
: m_data(other.m_data), m_partialCharges(other.m_partialCharges),
m_spectra(other.m_spectra), m_customElementMap(other.m_customElementMap),
m_elements(other.m_elements), m_positions2d(other.m_positions2d),
m_positions3d(other.m_positions3d), m_label(other.m_label),
m_coordinates3d(other.m_coordinates3d), m_timesteps(other.m_timesteps),
m_hybridizations(other.m_hybridizations),
m_positions3d(other.m_positions3d), m_atomLabels(other.m_atomLabels),
m_bondLabels(other.m_bondLabels), m_coordinates3d(other.m_coordinates3d),
m_timesteps(other.m_timesteps), m_hybridizations(other.m_hybridizations),
m_formalCharges(other.m_formalCharges), m_colors(other.m_colors),
m_vibrationFrequencies(other.m_vibrationFrequencies),
m_vibrationIRIntensities(other.m_vibrationIRIntensities),
Expand Down Expand Up @@ -79,7 +79,8 @@ Molecule::Molecule(const Molecule& other)

void Molecule::readProperties(const Molecule& other)
{
m_label = other.m_label;
m_atomLabels = other.m_atomLabels;
m_bondLabels = other.m_bondLabels;
m_colors = other.m_colors;
// merge data maps by iterating through other's map
for (auto it = other.m_data.constBegin(); it != other.m_data.constEnd();
Expand Down Expand Up @@ -134,9 +135,9 @@ Molecule::Molecule(Molecule&& other) noexcept
m_spectra(other.m_spectra),
m_customElementMap(std::move(other.m_customElementMap)),
m_elements(other.m_elements), m_positions2d(other.m_positions2d),
m_positions3d(other.m_positions3d), m_label(other.m_label),
m_coordinates3d(other.m_coordinates3d), m_timesteps(other.m_timesteps),
m_hybridizations(other.m_hybridizations),
m_positions3d(other.m_positions3d), m_atomLabels(other.m_atomLabels),
m_bondLabels(other.m_bondLabels), m_coordinates3d(other.m_coordinates3d),
m_timesteps(other.m_timesteps), m_hybridizations(other.m_hybridizations),
m_formalCharges(other.m_formalCharges), m_colors(other.m_colors),
m_vibrationFrequencies(other.m_vibrationFrequencies),
m_vibrationIRIntensities(other.m_vibrationIRIntensities),
Expand Down Expand Up @@ -176,7 +177,8 @@ Molecule& Molecule::operator=(const Molecule& other)
m_elements = other.m_elements;
m_positions2d = other.m_positions2d;
m_positions3d = other.m_positions3d;
m_label = other.m_label;
m_atomLabels = other.m_atomLabels;
m_bondLabels = other.m_bondLabels;
m_coordinates3d = other.m_coordinates3d;
m_timesteps = other.m_timesteps;
m_hybridizations = other.m_hybridizations;
Expand Down Expand Up @@ -238,7 +240,8 @@ Molecule& Molecule::operator=(Molecule&& other) noexcept
m_elements = other.m_elements;
m_positions2d = other.m_positions2d;
m_positions3d = other.m_positions3d;
m_label = other.m_label;
m_atomLabels = other.m_atomLabels;
m_bondLabels = other.m_bondLabels;
m_coordinates3d = other.m_coordinates3d;
m_timesteps = other.m_timesteps;
m_hybridizations = other.m_hybridizations;
Expand Down Expand Up @@ -646,12 +649,13 @@ void Molecule::clearAtoms()
{
m_positions2d.clear();
m_positions3d.clear();
m_label.clear();
m_atomLabels.clear();
m_hybridizations.clear();
m_formalCharges.clear();
m_colors.clear();
m_atomicNumbers.clear();
m_bondOrders.clear();
m_bondLabels.clear();
m_graph.clear();
m_partialCharges.clear();
m_elements.reset();
Expand Down
91 changes: 78 additions & 13 deletions avogadro/core/molecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,27 @@ class AVOGADROCORE_EXPORT Molecule
*/
bool setAtomPosition3d(Index atomId, const Vector3& pos);

std::string label(Index atomId) const;
bool setLabel(const Core::Array<std::string>& label);
bool setLabel(Index atomId, const std::string& label);
/**
* @return Any custom label for the requested atom.
* @param atomId The index of the atom.
*/
std::string atomLabel(Index atomId) const;
/**
* Set the custom label of a single atom.
* @param atomId The index of the atom to modify.
* @param label The new label of the atom.
* @return True on success, false otherwise.
*/
bool setAtomLabel(Index atomId, const std::string& label);

const Core::Array<std::string> atomLabels() const { return m_atomLabels; }

/**
* Set all the atom labels in the molecule.
* @param label The new label array. Must be of length atomCount().
* @return True on success, false otherwise.
*/
bool setAtomLabels(const Core::Array<std::string>& label);

/**
* Set whether the specified atom is selected or not.
Expand Down Expand Up @@ -404,6 +422,28 @@ class AVOGADROCORE_EXPORT Molecule
/** @return the bond between atomId1 and atomId2. */
BondType bond(Index atomId1, Index atomId2) const;

/**
* @return Any custom label for the requested bond.
* @param bondIndex The index of the bond.
*/
std::string bondLabel(Index bondIndex) const;
/**
* Set the custom label of a single bond.
* @param bondIndex The index of the bond to modify.
* @param label The new label of the bond.
* @return True on success, false otherwise.
*/
bool setBondLabel(Index bondIndex, const std::string& label);

const Core::Array<std::string> bondLabels() const { return m_bondLabels; }

/**
* Set all the atom labels in the molecule.
* @param label The new label array. Must be of length atomCount().
* @return True on success, false otherwise.
*/
bool setBondLabels(const Core::Array<std::string>& label);

/**
* @brief Get all bonds to @p a.
* @return A vector of bonds to the supplied atom @p a.
Expand Down Expand Up @@ -780,7 +820,8 @@ class AVOGADROCORE_EXPORT Molecule
//!< force fields)
Array<Vector2> m_positions2d;
Array<Vector3> m_positions3d;
Array<std::string> m_label;
Array<std::string> m_atomLabels;
Array<std::string> m_bondLabels;
Array<Array<Vector3>> m_coordinates3d; //!< Store conformers/trajectories.
Array<double> m_timesteps;
Array<AtomHybridization> m_hybridizations;
Expand Down Expand Up @@ -989,26 +1030,26 @@ inline bool Molecule::setAtomPosition3d(Index atomId, const Vector3& pos)
return false;
}

inline std::string Molecule::label(Index atomId) const
inline std::string Molecule::atomLabel(Index atomId) const
{
return atomId < m_label.size() ? m_label[atomId] : "";
return atomId < m_atomLabels.size() ? m_atomLabels[atomId] : "";
}

inline bool Molecule::setLabel(const Core::Array<std::string>& label)
inline bool Molecule::setAtomLabels(const Core::Array<std::string>& labels)
{
if (label.size() == atomCount() || label.size() == 0) {
m_label = label;
if (labels.size() == atomCount() || labels.size() == 0) {
m_atomLabels = labels;
return true;
}
return false;
}

inline bool Molecule::setLabel(Index atomId, const std::string& label)
inline bool Molecule::setAtomLabel(Index atomId, const std::string& label)
{
if (atomId < atomCount()) {
if (atomId >= m_label.size())
m_label.resize(atomCount(), "");
m_label[atomId] = label;
if (atomId >= m_atomLabels.size())
m_atomLabels.resize(atomCount(), "");
m_atomLabels[atomId] = label;
return true;
}
return false;
Expand Down Expand Up @@ -1086,6 +1127,30 @@ inline const Array<unsigned char>& Molecule::bondOrders() const
return m_bondOrders;
}

inline std::string Molecule::bondLabel(Index bondId) const
{
return bondId < m_bondLabels.size() ? m_bondLabels[bondId] : "";
}

inline bool Molecule::setBondLabels(const Core::Array<std::string>& labels)
{
if (labels.size() == atomCount() || labels.size() == 0) {
m_bondLabels = labels;
return true;
}
return false;
}

inline bool Molecule::setBondLabel(Index bondId, const std::string& label)
{
if (bondId < bondCount()) {
if (bondId >= m_bondLabels.size())
m_bondLabels.resize(bondCount(), "");
m_bondLabels[bondId] = label;
return true;
}
return false;
}
inline const Graph& Molecule::graph() const
{
return m_graph;
Expand Down
33 changes: 27 additions & 6 deletions avogadro/io/cjsonformat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ bool CjsonFormat::deserialize(std::istream& file, Molecule& molecule,
json labels = atoms["labels"];
if (labels.is_array() && labels.size() == atomCount) {
for (size_t i = 0; i < atomCount; ++i) {
molecule.atom(i).setLabel(labels[i]);
molecule.setAtomLabel(i, labels[i]);
}
}

Expand Down Expand Up @@ -239,6 +239,14 @@ bool CjsonFormat::deserialize(std::istream& file, Molecule& molecule,
molecule.bond(i).setOrder(static_cast<int>(order[i]));
}
}

// are there bond labels?
json bondLabels = bonds["labels"];
if (bondLabels.is_array() && bondLabels.size() == molecule.bondCount()) {
for (unsigned int i = 0; i < molecule.bondCount(); ++i) {
molecule.setBondLabel(i, bondLabels[i]);
}
}
}

// residues are optional, but should be loaded
Expand Down Expand Up @@ -1051,12 +1059,15 @@ bool CjsonFormat::serialize(std::ostream& file, const Molecule& molecule,
}
}

// labels
json labels;
for (size_t i = 0; i < molecule.atomCount(); ++i) {
labels.push_back(molecule.label(i));
// check for atom labels
Array atomLabels = molecule.atomLabels();
if (atomLabels.size() == molecule.atomCount()) {
json labels;
for (Index i = 0; i < molecule.atomCount(); ++i) {
labels.push_back(atomLabels[i]);
}
root["atoms"]["labels"] = labels;
}
root["atoms"]["labels"] = labels;

// formal charges
json formalCharges;
Expand Down Expand Up @@ -1086,6 +1097,16 @@ bool CjsonFormat::serialize(std::ostream& file, const Molecule& molecule,
}
root["bonds"]["connections"]["index"] = connections;
root["bonds"]["order"] = order;

// check if there are bond labels
Array bondLabels = molecule.bondLabels();
if (bondLabels.size() == molecule.bondCount()) {
json labels;
for (Index i = 0; i < molecule.bondCount(); ++i) {
labels.push_back(bondLabels[i]);
}
root["bonds"]["labels"] = labels;
}
}

// Create and populate any residue arrays
Expand Down
Loading

0 comments on commit 762a0cb

Please sign in to comment.