mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* update .gitignore * foundation for 3D descriptors move PBF into core * cleanup work * a bit more cleanup * move the principal moments calc to MolTransforms * cleanup * cleanups * add caching of the principal moments and values * do not include the 3D descriptors in MolDescriptors.h * the properties are computed * add PMI descriptors and tests * add tests for NPR descriptors * return 0 when the largest PMI is zero * PMI edge case tests * NPR edge case tests * PBF edge case tests * PBF edge case tests * more edge cases * add a few more 3d descriptors * add defns to docs * tests for the new descriptors * add versions to new descriptors * add 3d descriptors to python wrapper * add eigen support to the travis build * try to get non-windows builds working * remove computeCovarianceMatrix() from java wrapper * make pmi property names "private"
207 lines
6.1 KiB
C++
207 lines
6.1 KiB
C++
//
|
|
// Copyright (C) 2016 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/MolTransforms/MolTransforms.h>
|
|
#include <Geometry/point.h>
|
|
|
|
#include "PMI.h"
|
|
|
|
#include <Eigen/Dense>
|
|
|
|
namespace RDKit {
|
|
namespace Descriptors{
|
|
namespace {
|
|
|
|
bool getMoments(const ROMol& mol,int confId, bool useAtomicMasses,
|
|
double &pm1, double &pm2, double &pm3){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
const char *pn1 = useAtomicMasses ? "_PMI1_mass" : "_PMI1";
|
|
const char *pn2 = useAtomicMasses ? "_PMI2_mass" : "_PMI2";
|
|
const char *pn3 = useAtomicMasses ? "_PMI3_mass" : "_PMI3";
|
|
|
|
if(mol.hasProp(pn1) && mol.hasProp(pn2) && mol.hasProp(pn3) ) {
|
|
mol.getProp(pn1,pm1);
|
|
mol.getProp(pn2,pm2);
|
|
mol.getProp(pn3,pm3);
|
|
return true;
|
|
}
|
|
|
|
const Conformer &conf=mol.getConformer(confId);
|
|
|
|
Eigen::Matrix3d axes;
|
|
Eigen::Vector3d moments;
|
|
bool res;
|
|
bool ignoreHs=false;
|
|
if(useAtomicMasses){
|
|
std::vector<double> weights;
|
|
weights.resize(mol.getNumAtoms());
|
|
for(ROMol::ConstAtomIterator cai=mol.beginAtoms();
|
|
cai!=mol.endAtoms();++cai){
|
|
weights[(*cai)->getIdx()] = (*cai)->getMass();
|
|
}
|
|
res = MolTransforms::computePrincipalAxesAndMoments(conf,axes,moments,ignoreHs,false,&weights);
|
|
} else {
|
|
res = MolTransforms::computePrincipalAxesAndMoments(conf,axes,moments,ignoreHs);
|
|
}
|
|
if(res){
|
|
pm1 = moments(0);
|
|
pm2 = moments(1);
|
|
pm3 = moments(2);
|
|
//std::cerr<<" moments: "<<pm1<<" "<<pm2<<" "<<pm3<<std::endl;
|
|
mol.setProp(pn1,pm1,true);
|
|
mol.setProp(pn2,pm2,true);
|
|
mol.setProp(pn3,pm3,true);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
} // end of anonymous namespace
|
|
|
|
double NPR1(const ROMol& mol, int confId, bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm3<1e-8) return 0.0;
|
|
return pm1/pm3;
|
|
}
|
|
double NPR2(const ROMol& mol, int confId, bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm3<1e-8) return 0.0;
|
|
return pm2/pm3;
|
|
}
|
|
double PMI1(const ROMol& mol, int confId, bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
return pm1;
|
|
}
|
|
double PMI2(const ROMol& mol, int confId, bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
return pm2;
|
|
}
|
|
double PMI3(const ROMol& mol, int confId, bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
return pm3;
|
|
}
|
|
|
|
double radiusOfGyration(const ROMol& mol,int confId,
|
|
bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
double denom;
|
|
if(useAtomicMasses){
|
|
denom = 0.0;
|
|
for(ROMol::ConstAtomIterator cai = mol.beginAtoms();
|
|
cai!=mol.endAtoms();++cai){
|
|
denom += (*cai)->getMass();
|
|
}
|
|
} else {
|
|
denom = mol.getNumAtoms();
|
|
}
|
|
if(denom<1e-8) return 0.0;
|
|
if(pm1<1e-4) {
|
|
// planar
|
|
return sqrt(sqrt(pm2*pm3)/denom);
|
|
} else {
|
|
return sqrt(2*M_PI*pow(pm1*pm2*pm3,1./3)/denom);
|
|
}
|
|
}
|
|
|
|
double inertialShapeFactor(const ROMol& mol,int confId,
|
|
bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm1<1e-4 || pm3<1e-4) {
|
|
// planar or no coordinates
|
|
return 0.0;
|
|
} else {
|
|
return pm2 / (pm1*pm3);
|
|
}
|
|
}
|
|
double eccentricity(const ROMol& mol,int confId,
|
|
bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm3<1e-4) {
|
|
// no coordinates
|
|
return 0.0;
|
|
} else {
|
|
return sqrt(pm3*pm3-pm1*pm1) / pm3;
|
|
}
|
|
}
|
|
double asphericity(const ROMol& mol,int confId,
|
|
bool useAtomicMasses){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm3<1e-4) {
|
|
// no coordinates
|
|
return 0.0;
|
|
} else {
|
|
return 0.5 * (pow(pm3-pm2,2) + pow(pm3-pm1,2) + pow(pm2-pm1,2))/
|
|
(pm1*pm1+pm2*pm2+pm3*pm3);
|
|
}
|
|
}
|
|
double spherocityIndex(const ROMol& mol,int confId){
|
|
PRECONDITION(mol.getNumConformers()>=1,"molecule has no conformers");
|
|
bool useAtomicMasses=false;
|
|
double pm1,pm2,pm3;
|
|
if(!getMoments(mol,confId,useAtomicMasses,pm1,pm2,pm3)){
|
|
// the eigenvector calculation failed
|
|
return 0.0; // FIX: throw an exception here?
|
|
}
|
|
if(pm3<1e-4) {
|
|
// no coordinates
|
|
return 0.0;
|
|
} else {
|
|
return 3. * pm1 / (pm1+pm2+pm3);
|
|
}
|
|
}
|
|
|
|
|
|
} // end of Descriptors namespace
|
|
} // end of RDKit namespace
|