mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
363 lines
9.6 KiB
C++
363 lines
9.6 KiB
C++
// $Id$
|
|
//
|
|
// Copyright (C) 2012 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 <RDGeneral/Invariant.h>
|
|
#include <GraphMol/GraphMol.h>
|
|
#include <GraphMol/PeriodicTable.h>
|
|
#include <GraphMol/MolOps.h>
|
|
#include <GraphMol/Subgraphs/Subgraphs.h>
|
|
#include "MolDescriptors.h"
|
|
#include "ConnectivityDescriptors.h"
|
|
|
|
namespace RDKit {
|
|
namespace Descriptors {
|
|
namespace detail {
|
|
void hkDeltas(const ROMol &mol, std::vector<double> &deltas, bool force) {
|
|
PRECONDITION(deltas.size() >= mol.getNumAtoms(), "bad vector size");
|
|
if (!force && mol.hasProp(common_properties::_connectivityHKDeltas)) {
|
|
mol.getProp(common_properties::_connectivityHKDeltas, deltas);
|
|
return;
|
|
}
|
|
const PeriodicTable *tbl = PeriodicTable::getTable();
|
|
ROMol::VERTEX_ITER atBegin, atEnd;
|
|
boost::tie(atBegin, atEnd) = mol.getVertices();
|
|
while (atBegin != atEnd) {
|
|
ATOM_SPTR at = mol[*atBegin];
|
|
unsigned int n = at->getAtomicNum();
|
|
if (n <= 1) {
|
|
deltas[at->getIdx()] = 0;
|
|
} else if (n <= 10) {
|
|
deltas[at->getIdx()] = tbl->getNouterElecs(n) - at->getTotalNumHs();
|
|
} else {
|
|
deltas[at->getIdx()] =
|
|
double(tbl->getNouterElecs(n) - at->getTotalNumHs()) /
|
|
(n - tbl->getNouterElecs(n) - 1);
|
|
}
|
|
if (deltas[at->getIdx()] != 0.0)
|
|
deltas[at->getIdx()] = 1. / sqrt(deltas[at->getIdx()]);
|
|
++atBegin;
|
|
}
|
|
mol.setProp(common_properties::_connectivityHKDeltas, deltas, true);
|
|
}
|
|
|
|
void nVals(const ROMol &mol, std::vector<double> &nVs, bool force) {
|
|
PRECONDITION(nVs.size() >= mol.getNumAtoms(), "bad vector size");
|
|
if (!force && mol.hasProp(common_properties::_connectivityNVals)) {
|
|
mol.getProp(common_properties::_connectivityNVals, nVs);
|
|
return;
|
|
}
|
|
const PeriodicTable *tbl = PeriodicTable::getTable();
|
|
ROMol::VERTEX_ITER atBegin, atEnd;
|
|
boost::tie(atBegin, atEnd) = mol.getVertices();
|
|
while (atBegin != atEnd) {
|
|
ATOM_SPTR at = mol[*atBegin];
|
|
double v = tbl->getNouterElecs(at->getAtomicNum()) - at->getTotalNumHs();
|
|
if (v != 0.0) {
|
|
v = 1. / sqrt(v);
|
|
}
|
|
nVs[at->getIdx()] = v;
|
|
++atBegin;
|
|
}
|
|
mol.setProp(common_properties::_connectivityNVals, nVs, true);
|
|
}
|
|
|
|
double getAlpha(const Atom &atom, bool &found) {
|
|
double res = 0.0;
|
|
found = false;
|
|
switch (atom.getAtomicNum()) {
|
|
case 1:
|
|
res = 0.0;
|
|
found = true;
|
|
break;
|
|
case 6:
|
|
switch (atom.getHybridization()) {
|
|
case Atom::SP:
|
|
res = -0.22;
|
|
found = true;
|
|
break;
|
|
case Atom::SP2:
|
|
res = -0.13;
|
|
found = true;
|
|
break;
|
|
default:
|
|
res = 0.00;
|
|
found = true;
|
|
};
|
|
break;
|
|
case 7:
|
|
switch (atom.getHybridization()) {
|
|
case Atom::SP:
|
|
res = -0.29;
|
|
found = true;
|
|
break;
|
|
case Atom::SP2:
|
|
res = -0.20;
|
|
found = true;
|
|
break;
|
|
default:
|
|
res = -0.04;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 8:
|
|
switch (atom.getHybridization()) {
|
|
case Atom::SP2:
|
|
res = -0.20;
|
|
found = true;
|
|
break;
|
|
default:
|
|
res = -0.04;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 9:
|
|
switch (atom.getHybridization()) {
|
|
default:
|
|
res = -0.07;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 15:
|
|
switch (atom.getHybridization()) {
|
|
case Atom::SP2:
|
|
res = 0.30;
|
|
found = true;
|
|
break;
|
|
default:
|
|
res = 0.43;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 16:
|
|
switch (atom.getHybridization()) {
|
|
case Atom::SP2:
|
|
res = 0.22;
|
|
found = true;
|
|
break;
|
|
default:
|
|
res = 0.35;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 17:
|
|
switch (atom.getHybridization()) {
|
|
default:
|
|
res = 0.29;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 35:
|
|
switch (atom.getHybridization()) {
|
|
default:
|
|
res = 0.48;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
case 53:
|
|
switch (atom.getHybridization()) {
|
|
default:
|
|
res = 0.73;
|
|
found = true;
|
|
break;
|
|
};
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
} // end of detail namespace
|
|
|
|
double calcChiNv(const ROMol &mol, unsigned int n, bool force) {
|
|
std::vector<double> hkDs(mol.getNumAtoms());
|
|
detail::hkDeltas(mol, hkDs, force);
|
|
PATH_LIST ps = findAllPathsOfLengthN(mol, n + 1, false);
|
|
double res = 0.0;
|
|
BOOST_FOREACH (PATH_TYPE p, ps) {
|
|
TEST_ASSERT(p.size() == n + 1);
|
|
double accum = 1.0;
|
|
for (unsigned int i = 0; i < n; ++i) {
|
|
accum *= hkDs[p[i]];
|
|
}
|
|
// only push on the last element if this isn't a ring; this was github 463:
|
|
if (p[n] != p[0]) {
|
|
accum *= hkDs[p[n]];
|
|
}
|
|
res += accum;
|
|
}
|
|
return res;
|
|
}
|
|
double calcChiNn(const ROMol &mol, unsigned int n, bool force) {
|
|
std::vector<double> nVs(mol.getNumAtoms());
|
|
detail::nVals(mol, nVs, force);
|
|
PATH_LIST ps = findAllPathsOfLengthN(mol, n + 1, false);
|
|
double res = 0.0;
|
|
BOOST_FOREACH (PATH_TYPE p, ps) {
|
|
TEST_ASSERT(p.size() == n + 1);
|
|
double accum = 1.0;
|
|
for (unsigned int i = 0; i < n; ++i) {
|
|
accum *= nVs[p[i]];
|
|
}
|
|
// only push on the last element if this isn't a ring; this was github 463:
|
|
if (p[n] != p[0]) {
|
|
accum *= nVs[p[n]];
|
|
}
|
|
|
|
res += accum;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
double calcChi0v(const ROMol &mol, bool force) {
|
|
std::vector<double> hkDs(mol.getNumAtoms());
|
|
detail::hkDeltas(mol, hkDs, force);
|
|
return std::accumulate(hkDs.begin(), hkDs.end(), 0.0);
|
|
};
|
|
double calcChi1v(const ROMol &mol, bool force) {
|
|
std::vector<double> hkDs(mol.getNumAtoms());
|
|
detail::hkDeltas(mol, hkDs, force);
|
|
|
|
double res = 0.0;
|
|
ROMol::EDGE_ITER firstB, lastB;
|
|
boost::tie(firstB, lastB) = mol.getEdges();
|
|
while (firstB != lastB) {
|
|
BOND_SPTR bond = mol[*firstB];
|
|
res += hkDs[bond->getBeginAtomIdx()] * hkDs[bond->getEndAtomIdx()];
|
|
++firstB;
|
|
}
|
|
return res;
|
|
};
|
|
double calcChi2v(const ROMol &mol, bool force) {
|
|
return calcChiNv(mol, 2, force);
|
|
};
|
|
double calcChi3v(const ROMol &mol, bool force) {
|
|
return calcChiNv(mol, 3, force);
|
|
};
|
|
double calcChi4v(const ROMol &mol, bool force) {
|
|
return calcChiNv(mol, 4, force);
|
|
};
|
|
|
|
double calcChi0n(const ROMol &mol, bool force) {
|
|
std::vector<double> nVs(mol.getNumAtoms());
|
|
detail::nVals(mol, nVs, force);
|
|
return std::accumulate(nVs.begin(), nVs.end(), 0.0);
|
|
};
|
|
double calcChi1n(const ROMol &mol, bool force) {
|
|
std::vector<double> nVs(mol.getNumAtoms());
|
|
detail::nVals(mol, nVs, force);
|
|
|
|
double res = 0.0;
|
|
ROMol::EDGE_ITER firstB, lastB;
|
|
boost::tie(firstB, lastB) = mol.getEdges();
|
|
while (firstB != lastB) {
|
|
BOND_SPTR bond = mol[*firstB];
|
|
res += nVs[bond->getBeginAtomIdx()] * nVs[bond->getEndAtomIdx()];
|
|
++firstB;
|
|
}
|
|
return res;
|
|
};
|
|
double calcChi2n(const ROMol &mol, bool force) {
|
|
return calcChiNn(mol, 2, force);
|
|
};
|
|
double calcChi3n(const ROMol &mol, bool force) {
|
|
return calcChiNn(mol, 3, force);
|
|
};
|
|
double calcChi4n(const ROMol &mol, bool force) {
|
|
return calcChiNn(mol, 4, force);
|
|
};
|
|
|
|
double calcHallKierAlpha(const ROMol &mol, std::vector<double> *atomContribs) {
|
|
PRECONDITION(!atomContribs || atomContribs->size() >= mol.getNumAtoms(),
|
|
"bad atomContribs vector");
|
|
const PeriodicTable *tbl = PeriodicTable::getTable();
|
|
double alphaSum = 0.0;
|
|
double rC = tbl->getRb0(6);
|
|
ROMol::VERTEX_ITER atBegin, atEnd;
|
|
boost::tie(atBegin, atEnd) = mol.getVertices();
|
|
while (atBegin != atEnd) {
|
|
ATOM_SPTR at = mol[*atBegin];
|
|
++atBegin;
|
|
unsigned int n = at->getAtomicNum();
|
|
if (!n) continue;
|
|
bool found;
|
|
double alpha = detail::getAlpha(*(at.get()), found);
|
|
if (!found) {
|
|
double rA = tbl->getRb0(n);
|
|
alpha = rA / rC - 1.0;
|
|
}
|
|
alphaSum += alpha;
|
|
if (atomContribs) (*atomContribs)[at->getIdx()] = alpha;
|
|
}
|
|
return alphaSum;
|
|
};
|
|
|
|
namespace {
|
|
double kappa1Helper(double P1, double A, double alpha) {
|
|
double denom = P1 + alpha;
|
|
double kappa = 0.0;
|
|
if (denom) {
|
|
kappa = (A + alpha) * (A + alpha - 1) * (A + alpha - 1) / (denom * denom);
|
|
}
|
|
return kappa;
|
|
}
|
|
double kappa2Helper(double P2, double A, double alpha) {
|
|
double denom = (P2 + alpha) * (P2 + alpha);
|
|
double kappa = 0.0;
|
|
if (denom) {
|
|
kappa = (A + alpha - 1) * (A + alpha - 2) * (A + alpha - 2) / denom;
|
|
}
|
|
return kappa;
|
|
}
|
|
double kappa3Helper(double P3, int A, double alpha) {
|
|
double denom = (P3 + alpha) * (P3 + alpha);
|
|
double kappa = 0.0;
|
|
if (denom) {
|
|
if (A % 2) {
|
|
kappa = (A + alpha - 1) * (A + alpha - 3) * (A + alpha - 3) / denom;
|
|
} else {
|
|
kappa = (A + alpha - 2) * (A + alpha - 3) * (A + alpha - 3) / denom;
|
|
}
|
|
}
|
|
return kappa;
|
|
}
|
|
} // end of anonymous namespace
|
|
|
|
double calcKappa1(const ROMol &mol) {
|
|
double P1 = mol.getNumBonds();
|
|
double A = mol.getNumHeavyAtoms();
|
|
double alpha = calcHallKierAlpha(mol);
|
|
double kappa = kappa1Helper(P1, A, alpha);
|
|
return kappa;
|
|
}
|
|
double calcKappa2(const ROMol &mol) {
|
|
PATH_LIST ps = findAllPathsOfLengthN(mol, 2);
|
|
double P2 = ps.size();
|
|
double A = mol.getNumHeavyAtoms();
|
|
double alpha = calcHallKierAlpha(mol);
|
|
double kappa = kappa2Helper(P2, A, alpha);
|
|
return kappa;
|
|
}
|
|
double calcKappa3(const ROMol &mol) {
|
|
double P3 = findAllPathsOfLengthN(mol, 3).size();
|
|
int A = mol.getNumHeavyAtoms();
|
|
double alpha = calcHallKierAlpha(mol);
|
|
double kappa = kappa3Helper(P3, A, alpha);
|
|
return kappa;
|
|
}
|
|
} // end of namespace Descriptors
|
|
}
|