// $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 #include namespace RDKit { namespace Descriptors { std::vector calcMQNs(const ROMol& mol, bool force) { RDUNUSED_PARAM(force); // 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 BOOST_FOREACH (const INT_VECT& 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