Files
rdkit/Code/GraphMol/StructChecker/Utilites.cpp
2026-02-09 12:10:50 +01:00

166 lines
4.3 KiB
C++

//
// Copyright (C) 2016-2022 Novartis Institutes for BioMedical Research and
// other RDKit contributors
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include "../../RDGeneral/types.h"
#include "../../Geometry/point.h"
#include "Utilites.h"
#include <algorithm>
#include <tuple>
namespace RDKit {
namespace StructureCheck {
void SetupNeighbourhood(const ROMol &mol,
std::vector<Neighbourhood> &neighbours) {
neighbours.clear();
neighbours.resize(mol.getNumAtoms());
for (unsigned i = 0; i < mol.getNumBonds(); i++) {
const Bond *bond = mol.getBondWithIdx(i);
unsigned a1 = bond->getBeginAtomIdx();
unsigned a2 = bond->getEndAtomIdx();
neighbours[a1].Atoms.push_back(a2);
neighbours[a1].Bonds.push_back(i);
neighbours[a2].Atoms.push_back(a1);
neighbours[a2].Bonds.push_back(i);
}
}
bool getMolAtomPoints(const ROMol &mol, std::vector<RDGeom::Point3D> &atomPoint,
bool twod) {
bool non_zero_z = false;
atomPoint.resize(mol.getNumAtoms());
// take X,Y,Z coordinates of each atom
if (0 != mol.getNumConformers()) {
for (auto cnfi = mol.beginConformers(); cnfi != mol.endConformers();
cnfi++) {
const Conformer &conf = **cnfi; // mol.getConformer(confId);
if (twod || conf.is3D()) {
for (unsigned i = 0; i < mol.getNumAtoms(); i++) {
atomPoint[i] = conf.getAtomPos(i);
if (fabs(atomPoint[i].z) >= 1.e-7) {
non_zero_z = true;
}
}
break;
}
}
}
if (atomPoint.empty()) { // compute XYZ
// TODO:
// ???? ..........
}
return non_zero_z;
}
typedef std::tuple<std::string, int, int, int> NbrData;
bool lessTuple(const NbrData &left, const NbrData &right) {
if (std::get<0>(left) < std::get<0>(right)) {
return true;
}
if (std::get<0>(left) > std::get<0>(right)) {
return false;
}
if (std::get<1>(left) < std::get<1>(right)) {
return true;
}
if (std::get<1>(left) > std::get<1>(right)) {
return false;
}
if (std::get<2>(left) < std::get<2>(right)) {
return true;
}
if (std::get<2>(left) > std::get<2>(right)) {
return false;
}
if (std::get<3>(left) < std::get<3>(right)) {
return true;
}
return false;
}
std::string LogNeighbourhood(
const ROMol &mol, unsigned int idx,
const std::vector<Neighbourhood> &neighbour_array) {
std::stringstream oss;
// FIX ME turn into utility func?
std::string name("");
mol.getPropIfPresent(common_properties::_Name, name);
oss << "atom '" << name << "' idx=" << idx << " AA: ";
const Atom &atm = *mol.getAtomWithIdx(idx);
oss << atm.getSymbol();
if (atm.getFormalCharge()) {
oss << (atm.getFormalCharge() > 0 ? "+" : "") << atm.getFormalCharge();
}
if (atm.getNumRadicalElectrons()) {
oss << atm.getNumRadicalElectrons();
}
// these neighbors should be sorted properly?
size_t numNbrs = neighbour_array[idx].Atoms.size();
// CHECK_INVARIANT(numNBrs == neighbour_array[idx].Bonds.size());
std::vector<NbrData> nbrs;
for (size_t i = 0; i < numNbrs; ++i) {
const Bond *bond = mol.getBondWithIdx(neighbour_array[idx].Bonds[i]);
const Atom &nbr = *mol.getAtomWithIdx(neighbour_array[idx].Atoms[i]);
nbrs.push_back(NbrData(nbr.getSymbol(), bond->getBondType(),
nbr.getFormalCharge(),
nbr.getNumRadicalElectrons()));
}
std::sort(nbrs.begin(), nbrs.end(), lessTuple);
for (auto &nbr : nbrs) {
std::string bs = "";
switch (std::get<1>(nbr)) {
case Bond::SINGLE:
bs = "-";
break;
case Bond::DOUBLE:
bs = "=";
break;
case Bond::TRIPLE:
bs = "#";
break;
case Bond::AROMATIC:
bs = "~";
break;
}
if (bs.size()) {
oss << "(" << bs << std::get<0>(nbr);
} else {
oss << "("
<< "?" << (int)std::get<1>(nbr) << "?" << std::get<0>(nbr);
}
if (std::get<2>(nbr)) {
oss << (std::get<2>(nbr) > 0 ? "+" : "") << std::get<2>(nbr);
}
if (std::get<3>(nbr)) {
oss << std::get<3>(nbr);
}
oss << ")";
}
return oss.str();
}
} // namespace StructureCheck
} // namespace RDKit