Files
rdkit/Code/GraphMol/Descriptors/MQN.cpp
Greg Landrum da6cd73168 Run clang-format across everything (#7849)
* run clang-format-18 across Code/*.cpp and Code/*.h

* run clang-format-18 across External
2024-09-26 13:39:02 +02:00

204 lines
4.8 KiB
C++

// $Id$
//
// Copyright (C) 2013 Greg Landrum
//
// @@ 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 <GraphMol/RDKitBase.h>
#include <GraphMol/Descriptors/MolDescriptors.h>
#include <GraphMol/Descriptors/Lipinski.h>
#include <vector>
#include <algorithm>
namespace RDKit {
namespace Descriptors {
std::vector<unsigned int> calcMQNs(const ROMol &mol, bool) {
// FIX: use force value to enable caching
std::vector<unsigned int> res(42, 0);
// ---------------------------------------------------
// atom-centered things
// Note: We're not doing exactly the same thing
// as the original paper on polarity counts
// since we're using different donor and acceptor
// definitions.
ROMol::VERTEX_ITER atBegin, atEnd;
boost::tie(atBegin, atEnd) = mol.getVertices();
while (atBegin != atEnd) {
const Atom *at = mol[*atBegin];
++atBegin;
unsigned int nHs = at->getTotalNumHs();
unsigned int nRings = mol.getRingInfo()->numAtomRings(at->getIdx());
switch (at->getAtomicNum()) {
case 0:
case 1:
break;
case 6:
res[0]++;
break;
case 9:
res[1]++;
break;
case 17:
res[2]++;
break;
case 35:
res[3]++;
break;
case 53:
res[4]++;
break;
case 16:
res[5]++;
break;
case 15:
res[6]++;
break;
case 7:
if (!nRings) {
res[7]++;
} else {
res[8]++;
}
if (at->getDegree() != 4) {
res[19]++; // number of acceptor sites
res[20]++; // number of acceptor atoms
}
if (nHs) {
res[21] += nHs; // number of donor sites
res[22]++; // number of donor atoms
}
break;
case 8:
if (!nRings) {
res[9]++;
} else {
res[10]++;
}
res[20]++; // number of acceptor atoms
if (at->getFormalCharge() != -1) {
res[19] += 2; // number of acceptor sites
} else {
res[19] += 3; // number of acceptor sites
}
if (nHs) {
res[21] += nHs; // number of donor sites
res[22]++; // number of donor atoms
}
break;
default:
break;
}
if (at->getFormalCharge() > 0) {
res[24]++; // positive charges
} else if (at->getFormalCharge() < 0) {
res[23]++; // negative charges
}
if (at->getAtomicNum() != 1) {
switch (at->getDegree()) {
case 1:
res[25]++;
break;
case 2:
if (!nRings) {
res[26]++;
} else {
res[29]++;
}
break;
case 3:
if (!nRings) {
res[27]++;
} else {
res[30]++;
}
break;
case 4:
if (!nRings) {
res[28]++;
} else {
res[31]++;
}
break;
}
if (nRings >= 2) {
res[40]++;
}
}
}
res[11] = mol.getNumHeavyAtoms();
// ---------------------------------------------------
// bond counts:
unsigned int nAromatic = 0;
ROMol::EDGE_ITER firstB, lastB;
boost::tie(firstB, lastB) = mol.getEdges();
while (firstB != lastB) {
const Bond *bond = mol[*firstB];
if (bond->getIsAromatic()) {
++nAromatic;
}
unsigned int nRings = mol.getRingInfo()->numBondRings(bond->getIdx());
switch (bond->getBondType()) {
case Bond::SINGLE:
if (!nRings) {
res[12]++;
} else {
res[15]++;
}
break;
case Bond::DOUBLE:
if (!nRings) {
res[13]++;
} else {
res[16]++;
}
break;
case Bond::TRIPLE:
if (!nRings) {
res[14]++;
} else {
res[17]++;
}
break;
default:
break;
}
if (nRings >= 2) {
res[41]++;
}
++firstB;
}
// rather than do the work to kekulize the molecule, we cheat
// by just dividing the number of aromatic bonds evenly among the
// cyclic single bond and cyclic double bond bins and give any
// remainder to the single bonds
res[15] += nAromatic / 2;
res[16] += nAromatic / 2;
if (nAromatic % 2) {
res[15]++;
}
res[18] = calcNumRotatableBonds(mol);
// ---------------------------------------------------
// ring size counts
for (const auto &iv : mol.getRingInfo()->atomRings()) {
if (iv.size() < 10) {
res[iv.size() + 29]++;
} else {
res[39]++;
}
}
return res;
}
} // end of namespace Descriptors
} // end of namespace RDKit