/// <summary> /// Calculates 11 directional and 6 non-directional WHIM descriptors for. /// the specified weighting scheme /// </summary> /// <returns>An ArrayList containing the descriptors in the order described above.</returns> public Result Calculate(IAtomContainer container, AtomWeightingType type = AtomWeightingType.Unity) { if (!GeometryUtil.Has3DCoordinates(container)) { throw new ThreeDRequiredException("Molecule must have 3D coordinates"); } double sum = 0.0; var ac = (IAtomContainer)container.Clone(); // do aromaticity detecttion for calculating polarizability later on //HueckelAromaticityDetector had = new HueckelAromaticityDetector(); //had.DetectAromaticity(ac); // get the coordinate matrix var cmat = Arrays.CreateJagged <double>(ac.Atoms.Count, 3); for (int i = 0; i < ac.Atoms.Count; i++) { var coords = ac.Atoms[i].Point3D.Value; cmat[i][0] = coords.X; cmat[i][1] = coords.Y; cmat[i][2] = coords.Z; } // set up the weight vector var wt = new double[ac.Atoms.Count]; IReadOnlyDictionary <int, double> hash = null; switch (type) { case AtomWeightingType.Mass: hash = hashatwt; break; case AtomWeightingType.Volume: hash = hashvdw; break; case AtomWeightingType.Electronegativity: hash = hasheneg; break; case AtomWeightingType.Polarizability: hash = hashpol; break; default: break; } switch (type) { case AtomWeightingType.Unity: for (int i = 0; i < ac.Atoms.Count; i++) { wt[i] = 1.0; } break; default: for (int i = 0; i < ac.Atoms.Count; i++) { wt[i] = hash[ac.Atoms[i].AtomicNumber]; } break; } PCA pcaobject = null; try { pcaobject = new PCA(cmat, wt); } catch (CDKException cdke) { Debug.WriteLine(cdke); } // directional WHIM's var lambda = pcaobject.GetEigenvalues(); var gamma = new double[3]; var nu = new double[3]; var eta = new double[3]; for (int i = 0; i < 3; i++) { sum += lambda[i]; } for (int i = 0; i < 3; i++) { nu[i] = lambda[i] / sum; } var scores = pcaobject.GetScores(); for (int i = 0; i < 3; i++) { sum = 0.0; for (int j = 0; j < ac.Atoms.Count; j++) { sum += scores[j][i] * scores[j][i] * scores[j][i] * scores[j][i]; } sum = sum / (lambda[i] * lambda[i] * ac.Atoms.Count); eta[i] = 1.0 / sum; } // look for symmetric & asymmetric atoms for the gamma descriptor for (int i = 0; i < 3; i++) { double ns = 0.0; double na = 0.0; for (int j = 0; j < ac.Atoms.Count; j++) { bool foundmatch = false; for (int k = 0; k < ac.Atoms.Count; k++) { if (k == j) { continue; } if (scores[j][i] == -1 * scores[k][i]) { ns++; foundmatch = true; break; } } if (!foundmatch) { na++; } } var n = (double)ac.Atoms.Count; gamma[i] = -1.0 * ((ns / n) * Math.Log(ns / n) / Math.Log(2.0) + (na / n) * Math.Log(1.0 / n) / Math.Log(2.0)); gamma[i] = 1.0 / (1.0 + gamma[i]); } { // non directional WHIMS's var t = lambda[0] + lambda[1] + lambda[2]; var a = lambda[0] * lambda[1] + lambda[0] * lambda[2] + lambda[1] * lambda[2]; var v = t + a + lambda[0] * lambda[1] * lambda[2]; double k = 0.0; sum = 0.0; for (int i = 0; i < 3; i++) { sum += lambda[i]; } for (int i = 0; i < 3; i++) { k = (lambda[i] / sum) - (1.0 / 3.0); } k = k / (4.0 / 3.0); var g = Math.Pow(gamma[0] * gamma[1] * gamma[2], 1.0 / 3.0); var d = eta[0] + eta[1] + eta[2]; // return all the stuff we calculated return(new Result( lambda[0], lambda[1], lambda[2], nu[0], nu[1], gamma[0], gamma[1], gamma[2], eta[0], eta[1], eta[2], t, a, v, k, g, d)); } }