// $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 #include #include #include #include namespace RDKit { namespace Descriptors { std::vector calcMQNs(const ROMol& mol, bool) { // FIX: use force value to enable caching std::vector 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