├── weights ├── bond_weights.h4 ├── bond_weights.h5 ├── angle_weights.h5 ├── dihedral_weights.h5 └── nonbonds_weights.h5 ├── trained_models ├── bond_model.h5 ├── angle_model.h5 ├── dihedrals_model.h5 └── nonbonds_model.h5 ├── README.md ├── scripts ├── optimizer.py ├── models.py ├── predictor.py ├── xyz_to_zmat.py └── featurizer.py ├── LICENSE └── examples ├── predict.ipynb └── optimizer.ipynb /weights/bond_weights.h4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/weights/bond_weights.h4 -------------------------------------------------------------------------------- /weights/bond_weights.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/weights/bond_weights.h5 -------------------------------------------------------------------------------- /weights/angle_weights.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/weights/angle_weights.h5 -------------------------------------------------------------------------------- /trained_models/bond_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/trained_models/bond_model.h5 -------------------------------------------------------------------------------- /weights/dihedral_weights.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/weights/dihedral_weights.h5 -------------------------------------------------------------------------------- /weights/nonbonds_weights.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/weights/nonbonds_weights.h5 -------------------------------------------------------------------------------- /trained_models/angle_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/trained_models/angle_model.h5 -------------------------------------------------------------------------------- /trained_models/dihedrals_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/trained_models/dihedrals_model.h5 -------------------------------------------------------------------------------- /trained_models/nonbonds_model.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devalab/BAND-NN/HEAD/trained_models/nonbonds_model.h5 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BAND-NN 2 | 3 | BAND-NN is a deep learning architecture for prediction of atomization energy and for geometry optimization. 4 | 5 | #### Requirements: 6 | - Python3 7 | - Keras 8 | - Tensorflow 9 | - Numpy 10 | - Scipy 11 | 12 | #### Usage: 13 | - Examples for prediction and geometry optimization are provided in examples/ folder. 14 | - Required scripts in scripts/ folder. 15 | - Trained models and weights are provided in models/ and weights/ folders. 16 | 17 | 18 | -------------------------------------------------------------------------------- /scripts/optimizer.py: -------------------------------------------------------------------------------- 1 | import scipy.optimize as sop 2 | from predictor import * 3 | from xyz_to_zmat import * 4 | 5 | def optimize(coordinates,species,bonds): 6 | prediction_model = get_default_prediction_model() 7 | zparams,zconnect = get_zmat_from_coordinates(coordinates) 8 | optim_params = sop.minimize(optimizer_oracle,zparams,method='Nelder-Mead',args=(zconnect,species,bonds,prediction_model)) 9 | optimized_coordinates = coordinates = get_coordinates_from_zmat(optim_params['x'],zconnect) 10 | optimized_energy = optim_params['fun'] 11 | return optimized_coordinates, optimized_energy 12 | 13 | 14 | def optimizer_oracle(zparams,zconnect,species,bonds,prediction_model): 15 | coordinates=get_coordinates_from_zmat(zparams, zconnect) 16 | energy = predict_energy(prediction_model,coordinates,species,bonds) 17 | return energy 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Deva Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/models.py: -------------------------------------------------------------------------------- 1 | from keras.models import Sequential, Model 2 | from keras.layers import Dense, Activation, Input 3 | 4 | def get_bonds_model(): 5 | model = Sequential() 6 | model.add(Dense(128, activation='relu', input_dim=17)) 7 | model.add(Dense(256, activation='relu')) 8 | model.add(Dense(128, activation='relu')) 9 | model.add(Dense(1, activation='linear')) 10 | return model 11 | 12 | def get_angles_model(): 13 | model = Sequential() 14 | model.add(Dense(128, activation='relu', input_dim=27)) 15 | model.add(Dense(350, activation='relu')) 16 | model.add(Dense(128, activation='relu')) 17 | model.add(Dense(1, activation='linear')) 18 | return model 19 | 20 | def get_nonbonds_model(): 21 | model = Sequential() 22 | model.add(Dense(128, activation='relu', input_dim=17)) 23 | model.add(Dense(256, activation='relu')) 24 | model.add(Dense(128, activation='relu')) 25 | model.add(Dense(1, activation='linear')) 26 | return model 27 | 28 | def get_dihedrals_model(): 29 | model = Sequential() 30 | model.add(Dense(128, activation='relu', input_dim=38)) 31 | model.add(Dense(512, activation='relu')) 32 | model.add(Dense(128, activation='relu')) 33 | model.add(Dense(1, activation='linear')) 34 | return model 35 | -------------------------------------------------------------------------------- /scripts/predictor.py: -------------------------------------------------------------------------------- 1 | from models import * 2 | from featurizer import * 3 | 4 | def get_default_prediction_model(): 5 | bonds_model = get_bonds_model() 6 | bonds_model.load_weights('../weights/bond_weights.h5') 7 | 8 | angles_model = get_angles_model() 9 | angles_model.load_weights('../weights/angle_weights.h5') 10 | 11 | nonbonds_model = get_nonbonds_model() 12 | nonbonds_model.load_weights('../weights/nonbonds_weights.h5') 13 | 14 | dihedralangles_model = get_dihedrals_model() 15 | dihedralangles_model.load_weights('../weights/dihedral_weights.h5') 16 | 17 | model = {} 18 | model['bonds'] = bonds_model 19 | model['angles'] = angles_model 20 | model['nonbonds'] = nonbonds_model 21 | model['dihedrals'] = dihedralangles_model 22 | return model 23 | 24 | 25 | def predict_energy(model,coordinates,species,bonds): 26 | features = get_features(coordinates, species, bonds) 27 | bond_energies = model['bonds'].predict(features['bonds']) 28 | angle_energies = model['angles'].predict(features['angles']) 29 | nonbond_energies = model['nonbonds'].predict(features['nonbonds']) 30 | dihedral_energies = model['dihedrals'].predict(features['dihedrals']) 31 | energy = -1*(np.sum(bond_energies) + np.sum(angle_energies) + np.sum(nonbond_energies) + np.sum(dihedral_energies)) 32 | return energy -------------------------------------------------------------------------------- /scripts/xyz_to_zmat.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def get_zmat_from_coordinates(xyzarr): 4 | xyzarr = np.array(xyzarr) 5 | distmat = distance_matrix(xyzarr) 6 | zmat = [] 7 | npart, ncoord = xyzarr.shape 8 | rlist = [] 9 | alist = [] 10 | dlist = [] 11 | rconnect = [] 12 | aconnect = [] 13 | dconnect = [] 14 | 15 | if npart > 0: 16 | 17 | if npart > 1: 18 | # and the second, with distance from first 19 | rlist.append(distmat[0][1]) 20 | zmat.append([1,rlist[0]]) 21 | rconnect.append(1) 22 | 23 | if npart > 2: 24 | rconnect.append(1) 25 | rlist.append(distmat[0][2]) 26 | alist.append(angle(xyzarr, 2, 0, 1)) 27 | aconnect.append(2) 28 | zmat.append([1, rlist[1], 2, alist[0]]) 29 | 30 | 31 | if npart > 3: 32 | for i in range(3, npart): 33 | rconnect.append(i-2) 34 | aconnect.append(i-1) 35 | dconnect.append(i) 36 | rlist.append(distmat[i-3][i]) 37 | alist.append(angle(xyzarr, i, i-3, i-2)) 38 | dlist.append(dihedral(xyzarr, i, i-3, i-2, i-1)) 39 | zmat.append([i-2, rlist[i-1], i-1, alist[i-2], i, dlist[i-3]]) 40 | zparams = rlist+alist+dlist 41 | zconnect = [rconnect,aconnect,dconnect] 42 | return (zparams, zconnect) 43 | 44 | def get_coordinates_from_zmat(zparams, zconnect): 45 | 46 | rconnect = zconnect[0] 47 | aconnect = zconnect[1] 48 | dconnect = zconnect[2] 49 | 50 | rlist=[] 51 | alist=[] 52 | dlist=[] 53 | zparams = zparams.tolist() 54 | for i in range(len(rconnect)): 55 | rlist.append(zparams.pop(0)) 56 | for i in range(len(aconnect)): 57 | alist.append(zparams.pop(0)) 58 | for i in range(len(dconnect)): 59 | dlist.append(zparams.pop(0)) 60 | 61 | npart = len(rconnect) + 1 62 | 63 | xyzarr = np.zeros([npart, 3]) 64 | if (npart > 1): 65 | xyzarr[1] = [rlist[0], 0.0, 0.0] 66 | 67 | if (npart > 2): 68 | i = rconnect[1] - 1 69 | j = aconnect[0] - 1 70 | r = rlist[1] 71 | theta = alist[0] 72 | x = r * np.cos(theta) 73 | y = r * np.sin(theta) 74 | a_i = xyzarr[i] 75 | b_ij = xyzarr[j] - xyzarr[i] 76 | if (b_ij[0] < 0): 77 | x = a_i[0] - x 78 | y = a_i[1] - y 79 | else: 80 | x = a_i[0] + x 81 | y = a_i[1] + y 82 | xyzarr[2] = [x, y, 0.0] 83 | 84 | for n in range(3, npart): 85 | r = rlist[n-1] 86 | theta = alist[n-2] 87 | phi = dlist[n-3] - np.pi 88 | 89 | sinTheta = np.sin(theta) 90 | cosTheta = np.cos(theta) 91 | sinPhi = np.sin(phi) 92 | cosPhi = np.cos(phi) 93 | 94 | x = r * cosTheta 95 | y = r * cosPhi * sinTheta 96 | z = r * sinPhi * sinTheta 97 | 98 | i = rconnect[n-1] - 1 99 | j = aconnect[n-2] - 1 100 | k = dconnect[n-3] - 1 101 | a = xyzarr[k] 102 | b = xyzarr[j] 103 | c = xyzarr[i] 104 | 105 | ab = b - a 106 | bc = c - b 107 | bc = bc / np.linalg.norm(bc) 108 | nv = np.cross(ab, bc) 109 | nv = nv / np.linalg.norm(nv) 110 | ncbc = np.cross(nv, bc) 111 | 112 | new_x = c[0] - bc[0] * x + ncbc[0] * y + nv[0] * z 113 | new_y = c[1] - bc[1] * x + ncbc[1] * y + nv[1] * z 114 | new_z = c[2] - bc[2] * x + ncbc[2] * y + nv[2] * z 115 | xyzarr[n] = [new_x, new_y, new_z] 116 | 117 | return (xyzarr) 118 | 119 | 120 | def angle(xyzarr, i, j, k): 121 | rij = xyzarr[i] - xyzarr[j] 122 | rkj = xyzarr[k] - xyzarr[j] 123 | cos_theta = np.dot(rij, rkj) 124 | sin_theta = np.linalg.norm(np.cross(rij, rkj)) 125 | theta = np.arctan2(sin_theta, cos_theta) 126 | return theta 127 | 128 | def dihedral(xyzarr, i, j, k, l): 129 | rji = xyzarr[j] - xyzarr[i] 130 | rkj = xyzarr[k] - xyzarr[j] 131 | rlk = xyzarr[l] - xyzarr[k] 132 | v1 = np.cross(rji, rkj) 133 | v1 = v1 / np.linalg.norm(v1) 134 | v2 = np.cross(rlk, rkj) 135 | v2 = v2 / np.linalg.norm(v2) 136 | m1 = np.cross(v1, rkj) / np.linalg.norm(rkj) 137 | x = np.dot(v1, v2) 138 | y = np.dot(m1, v2) 139 | chi = np.arctan2(y, x) 140 | return chi 141 | 142 | 143 | 144 | def distance_matrix(xyzarr): 145 | npart, ncoord = xyzarr.shape 146 | dist_mat = np.zeros([npart, npart]) 147 | for i in range(npart): 148 | for j in range(0, i): 149 | rvec = xyzarr[i] - xyzarr[j] 150 | dist_mat[i][j] = dist_mat[j][i] = np.sqrt(np.dot(rvec, rvec)) 151 | return dist_mat 152 | -------------------------------------------------------------------------------- /examples/predict.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stderr", 12 | "output_type": "stream", 13 | "text": [ 14 | "Using TensorFlow backend.\n", 15 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:523: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 16 | " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n", 17 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:524: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 18 | " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n", 19 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 20 | " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n", 21 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:526: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 22 | " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n", 23 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:527: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 24 | " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n", 25 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:532: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 26 | " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n" 27 | ] 28 | } 29 | ], 30 | "source": [ 31 | "import sys\n", 32 | "sys.path.insert(0, '../codes/')\n", 33 | "\n", 34 | "from predictor import *" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 3, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "##Define coordinates, species, bond-connectivities\n", 44 | "species = ['C','H','H','H','C','H','H','H']\n", 45 | "\n", 46 | "coordinates =[\n", 47 | " [0.00000000 , 0.00000000 , 0.77129800],\n", 48 | " [ -0.50676600 , 0.87777700 , 1.15591600],\n", 49 | " [1.01356000 , -0.00001600 , 1.15591600],\n", 50 | " [ -0.50679400 , -0.87776100 , 1.15591600],\n", 51 | " [ 0.00000000 , 0.00000000 , -0.77129800],\n", 52 | " [ 0.50676600 , 0.87777700 , -1.15591600],\n", 53 | " [ 0.50679400 , -0.87776100 , -1.15591600],\n", 54 | " [ -1.01356000 , -0.00001600 , -1.15591600],\n", 55 | "]\n", 56 | "\n", 57 | "bond_connectivity_list = [\n", 58 | " [1,2,3,4],\n", 59 | " [0],\n", 60 | " [0],\n", 61 | " [0],\n", 62 | " [5,6,7,1],\n", 63 | " [4],\n", 64 | " [4],\n", 65 | " [4],\n", 66 | "]\n" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 5, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "prediction_model = get_default_prediction_model()\n", 76 | "energy = predict_energy(prediction_model,coordinates,species,bond_connectivity_list)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 6, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "data": { 86 | "text/plain": [ 87 | "-712.6748657226562" 88 | ] 89 | }, 90 | "execution_count": 6, 91 | "metadata": {}, 92 | "output_type": "execute_result" 93 | } 94 | ], 95 | "source": [ 96 | "energy" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [] 105 | } 106 | ], 107 | "metadata": { 108 | "kernelspec": { 109 | "display_name": "Python 3", 110 | "language": "python", 111 | "name": "python3" 112 | }, 113 | "language_info": { 114 | "codemirror_mode": { 115 | "name": "ipython", 116 | "version": 3 117 | }, 118 | "file_extension": ".py", 119 | "mimetype": "text/x-python", 120 | "name": "python", 121 | "nbconvert_exporter": "python", 122 | "pygments_lexer": "ipython3", 123 | "version": "3.5.2" 124 | } 125 | }, 126 | "nbformat": 4, 127 | "nbformat_minor": 2 128 | } 129 | -------------------------------------------------------------------------------- /examples/optimizer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stderr", 12 | "output_type": "stream", 13 | "text": [ 14 | "Using TensorFlow backend.\n", 15 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:523: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 16 | " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n", 17 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:524: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 18 | " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n", 19 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 20 | " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n", 21 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:526: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 22 | " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n", 23 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:527: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 24 | " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n", 25 | "/home/siddhartha.l/.local/lib/python3.5/site-packages/tensorflow/python/framework/dtypes.py:532: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n", 26 | " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n" 27 | ] 28 | } 29 | ], 30 | "source": [ 31 | "import sys\n", 32 | "sys.path.insert(0, '../codes/')\n", 33 | "\n", 34 | "from optimizer import *" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 7, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "##Define coordinates, species, bond-connectivities\n", 44 | "species = ['C','H','H','H','C','H','H','H']\n", 45 | "\n", 46 | "coordinates =[\n", 47 | " [0.00000000 , 0.00000000 , 0.77129800],\n", 48 | " [ -0.50676600 , 0.87777700 , 1.15591600],\n", 49 | " [1.01356000 , -0.00001600 , 1.15591600],\n", 50 | " [ -0.50679400 , -0.87776100 , 1.15591600],\n", 51 | " [ 0.00000000 , 0.00000000 , -0.77129800],\n", 52 | " [ 0.50676600 , 0.87777700 , -1.15591600],\n", 53 | " [ 0.50679400 , -0.87776100 , -1.15591600],\n", 54 | " [ -1.01356000 , -0.00001600 , -1.15591600],\n", 55 | "]\n", 56 | "\n", 57 | "bond_connectivity_list = [\n", 58 | " [1,2,3,4],\n", 59 | " [0],\n", 60 | " [0],\n", 61 | " [0],\n", 62 | " [5,6,7,1],\n", 63 | " [4],\n", 64 | " [4],\n", 65 | " [4],\n", 66 | "]\n" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 8, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "optimized_coordinates, optimized_energy = optimize(coordinates,species,bond_connectivity_list)" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 9, 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "data": { 85 | "text/plain": [ 86 | "array([[ 0. , 0. , 0. ],\n", 87 | " [ 1.19735647, 0. , 0. ],\n", 88 | " [-0.52967986, 0.90668132, 0. ],\n", 89 | " [-0.39766296, -0.58203678, 0.77830385],\n", 90 | " [ 0.48314809, -0.69678023, -1.15282571],\n", 91 | " [ 0.93321507, -0.07132722, -1.83114994],\n", 92 | " [-0.46507236, -1.1646854 , -1.49614691],\n", 93 | " [ 1.00911584, -1.63133558, -0.84990832]])" 94 | ] 95 | }, 96 | "execution_count": 9, 97 | "metadata": {}, 98 | "output_type": "execute_result" 99 | } 100 | ], 101 | "source": [ 102 | "optimized_coordinates" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 10, 108 | "metadata": {}, 109 | "outputs": [ 110 | { 111 | "data": { 112 | "text/plain": [ 113 | "-789.4651489257812" 114 | ] 115 | }, 116 | "execution_count": 10, 117 | "metadata": {}, 118 | "output_type": "execute_result" 119 | } 120 | ], 121 | "source": [ 122 | "optimized_energy" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [] 131 | } 132 | ], 133 | "metadata": { 134 | "kernelspec": { 135 | "display_name": "Python 3", 136 | "language": "python", 137 | "name": "python3" 138 | }, 139 | "language_info": { 140 | "codemirror_mode": { 141 | "name": "ipython", 142 | "version": 3 143 | }, 144 | "file_extension": ".py", 145 | "mimetype": "text/x-python", 146 | "name": "python", 147 | "nbconvert_exporter": "python", 148 | "pygments_lexer": "ipython3", 149 | "version": "3.5.2" 150 | } 151 | }, 152 | "nbformat": 4, 153 | "nbformat_minor": 2 154 | } 155 | -------------------------------------------------------------------------------- /scripts/featurizer.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def get_features(conformer,S,bond_connectivity_list): 4 | conformer=np.array(conformer) 5 | nonbondcutoff = 6 6 | 7 | bonds = generate_bondconnectivty_matrix(bond_connectivity_list) 8 | 9 | #Calculate the atomic environment vector for each atom 10 | atomic_envs = generate_atomic_env(bonds, S) 11 | 12 | #Calculate the sets of bonds and bond values 13 | bondlist, bonddistances = generate_bond_data(conformer, bonds) 14 | bondfeatures = generate_bond_features(bonddistances,bondlist,atomic_envs) 15 | 16 | #Calculate the 3 atom angle sets and angle values 17 | angles_list, angles = generate_angle_data(conformer, bonds) 18 | anglefeatures = generate_angle_features(angles,angles_list,atomic_envs,bondlist,bonddistances) 19 | 20 | #Calculate 4 atom dihedral sets and dihedral values 21 | dihedral_list, dihedral_angles = generate_dihedral_data(conformer,bonds) 22 | dihedralfeatures = generate_dihedralangle_features(dihedral_angles, dihedral_list, atomic_envs, bondlist, bonddistances, angles_list, angles) 23 | 24 | # Calculate the list of Non-bonds 25 | nonbond_list, nonbonddistances = generate_nonbond_data(conformer, bonds, nonbondcutoff) 26 | nonbondfeatures = generate_bond_features(nonbonddistances,nonbond_list,atomic_envs) 27 | 28 | # Zipping the data 29 | features = {} 30 | features['bonds'] = np.array(bondfeatures) 31 | features['angles'] = np.array(anglefeatures) 32 | features['nonbonds'] = np.array(nonbondfeatures) 33 | features['dihedrals'] = np.array(dihedralfeatures) 34 | return features 35 | 36 | 37 | def generate_bondconnectivty_matrix(bond_connectivity_list): 38 | bond_matrix = [[0 for i in range(len(bond_connectivity_list))] for j in range(len(bond_connectivity_list))] 39 | for i1 in range(len(bond_connectivity_list)): 40 | for i2 in bond_connectivity_list[i1]: 41 | bond_matrix[i1][i2] = 1 42 | bond_matrix[i2][i1] = 1 43 | return bond_matrix 44 | 45 | 46 | def generate_atomic_env(bonds, S): 47 | atomic_envs = [] 48 | for i in range(len(bonds)): 49 | atom_id = {'H':0, 'C':1, 'O':2, 'N':3 } 50 | atomtype = [0,0,0,0] 51 | atomtype[atom_id[S[i]]] = 1 52 | immediate_neighbour_count = [0,0,0,0] 53 | for j in range(len(bonds[i])): 54 | if(bonds[i][j] > 0): 55 | immediate_neighbour_count[atom_id[S[j]]] += 1 56 | atomic_envs.append(atomtype + immediate_neighbour_count) 57 | return atomic_envs 58 | 59 | 60 | def generate_bond_data(conformer,bonds): 61 | #Calculate the paiwise-distances among the atoms 62 | distance = [[0 for i in range(len(conformer))] for j in range(len(conformer))] 63 | for i in range(len(conformer)): 64 | for j in range(len(conformer)): 65 | distance[i][j] = np.linalg.norm(conformer[i]-conformer[j]) 66 | 67 | bondlist = [] 68 | bonddistances = [] 69 | for i in range(len(bonds)): 70 | for j in range(i): 71 | if(bonds[i][j] is 1): 72 | bondlist.append([i,j]) 73 | bonddistances.append(distance[i][j]) 74 | 75 | return bondlist, bonddistances 76 | 77 | def generate_bond_features(bonddistances, bondlist, atomtype): 78 | labels = [] 79 | for bond in range(len(bondlist)): 80 | bond_feature = [] 81 | if(atomtype[bondlist[bond][0]] > atomtype[bondlist[bond][1]]): 82 | bond_feature += atomtype[bondlist[bond][0]] + atomtype[bondlist[bond][1]] 83 | else: 84 | bond_feature += atomtype[bondlist[bond][1]] + atomtype[bondlist[bond][0]] 85 | bond_feature.append(bonddistances[bond]) 86 | labels.append(bond_feature) 87 | return labels 88 | 89 | 90 | def generate_angle_data(conformer,bonds): 91 | angles_list = [] 92 | for i in range(len(conformer)): 93 | for j in range(len(conformer)): 94 | for k in range(len(conformer)): 95 | if(j!=i and j!=k and i>k and bonds[i][j]!=0 and bonds[j][k]!=0): 96 | angles_list.append([i,j,k]) 97 | 98 | angles = [] 99 | for angle_triplet in angles_list: 100 | angle = get_angle(conformer[angle_triplet[0]], conformer[angle_triplet[1]], conformer[angle_triplet[2]]) 101 | angles.append(angle) 102 | return angles_list, angles 103 | 104 | 105 | def get_angle(coor1,coor2,coor3): 106 | ba =coor1 - coor2 107 | bc = coor3 - coor2 108 | cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc)) 109 | if cosine_angle > 1.0: 110 | cosine_angle=1.0 111 | elif cosine_angle < -1.0: 112 | cosine_angle=-1.0 113 | if cosine_angle <=1.0 and cosine_angle>=-1.0: 114 | angle = np.arccos(cosine_angle) 115 | if angle > np.pi: 116 | angle=2*(np.pi)-angle 117 | return angle 118 | 119 | def generate_angle_features(angles, angletype, atomtype,bondlist,bonddistances): 120 | labels = [] 121 | for angle in range(len(angletype)): 122 | anglefeature = [] 123 | if(atomtype[angletype[angle][0]] > atomtype[angletype[angle][2]]): 124 | anglefeature += atomtype[angletype[angle][0]] + atomtype[angletype[angle][2]] 125 | bondlen1 = get_bondlen(angletype[angle][0],angletype[angle][1],bondlist,bonddistances) 126 | bondlen2 = get_bondlen(angletype[angle][1],angletype[angle][2],bondlist,bonddistances) 127 | else: 128 | anglefeature += atomtype[angletype[angle][2]] + atomtype[angletype[angle][0]] 129 | bondlen1 = get_bondlen(angletype[angle][1],angletype[angle][2],bondlist,bonddistances) 130 | bondlen2 = get_bondlen(angletype[angle][0],angletype[angle][1],bondlist,bonddistances) 131 | 132 | anglefeature += atomtype[angletype[angle][1]] 133 | anglefeature += ([angles[angle],bondlen1,bondlen2]) 134 | labels.append(anglefeature) 135 | return labels 136 | 137 | def get_bondlen(i1,i2,bondtypelist,bondlenlist): 138 | try: 139 | index = bondtypelist.index([i1,i2]) 140 | except: 141 | index = bondtypelist.index([i2,i1]) 142 | return bondlenlist[index] 143 | 144 | def generate_nonbond_data(conformer,bonds,nonbondcutoff): 145 | #Calculate the paiwise-distances among the atoms 146 | distance = [[0 for i in range(len(conformer))] for j in range(len(conformer))] 147 | for i in range(len(conformer)): 148 | for j in range(len(conformer)): 149 | distance[i][j] = np.linalg.norm(conformer[i]-conformer[j]) 150 | nonbond_distances = [] 151 | nonbond_list = [] 152 | for i in range(len(conformer)): 153 | for j in range(len(conformer)): 154 | if(i > j and distance[i][j] < nonbondcutoff and (bonds[i][j] == 0 ) ): 155 | nonbond_list.append([i,j]) 156 | nonbond_distances.append(distance[i][j]) 157 | return nonbond_list, nonbond_distances 158 | 159 | def generate_dihedral_data(conformer,bonds): 160 | dihedral_list= [] 161 | for i in range(len(conformer)): 162 | for j in range(len(conformer)): 163 | for k in range(len(conformer)): 164 | for l in range(len(conformer)): 165 | if( i>l and i!=j and i!=k and j!=k and j!=l and k!=l and bonds[i][j] == 1 and bonds[j][k]==1 and bonds[k][l]==1): 166 | dihedral_list.append([i,j,k,l]) 167 | 168 | dihedrals = [] 169 | for dihed in dihedral_list: 170 | dihedral_angle = get_dihedral(conformer[dihed[0]],conformer[dihed[1]],conformer[dihed[2]],conformer[dihed[3]]) 171 | dihedrals.append(dihedral_angle) 172 | return dihedral_list,dihedrals 173 | 174 | def get_dihedral(p0, p1, p2, p3): 175 | b0=p0-p1 176 | b1=p2-p1 177 | b2=p3-p2 178 | 179 | b0xb1 = np.cross(b0,b1) 180 | b1xb2 = np.cross(b2,b1) 181 | 182 | b0xb1_x_b1xb2 = np.cross(b0xb1,b1xb2) 183 | y = np.dot(b0xb1_x_b1xb2, b1)*(1.0/np.linalg.norm(b1)) 184 | x = np.dot(b0xb1, b1xb2) 185 | return np.arctan2(y, x) 186 | 187 | def get_angleval(i1,i2,i3,angletypelist,anglevallist): 188 | try: 189 | index = angletypelist.index([i1,i2,i3]) 190 | except: 191 | index = angletypelist.index([i3,i2,i1]) 192 | 193 | return anglevallist[index] 194 | 195 | def generate_dihedralangle_features(dihedral_angles, dihedral_list, atomtype,bondtypelist,bondlenlist,angletypelist,anglevallist): 196 | labels = [] 197 | for dihedral in range(len(dihedral_angles)): 198 | dihedral_feature = [] 199 | if(atomtype[dihedral_list[dihedral][0]] > atomtype[dihedral_list[dihedral][3]]): 200 | index1 = 0 201 | index2 = 1 202 | index3 = 2 203 | index4 = 3 204 | else: 205 | index1 = 3 206 | index2 = 2 207 | index3 = 1 208 | index4 = 0 209 | 210 | dihedral_feature += atomtype[dihedral_list[dihedral][index1]] + atomtype[dihedral_list[dihedral][index2]] 211 | dihedral_feature += atomtype[dihedral_list[dihedral][index3]] + atomtype[dihedral_list[dihedral][index4]] 212 | bondlen1 = get_bondlen(dihedral_list[dihedral][index1],dihedral_list[dihedral][index2],bondtypelist,bondlenlist) 213 | bondlen2 = get_bondlen(dihedral_list[dihedral][index2],dihedral_list[dihedral][index3],bondtypelist,bondlenlist) 214 | bondlen3 = get_bondlen(dihedral_list[dihedral][index3],dihedral_list[dihedral][index4],bondtypelist,bondlenlist) 215 | angleval1 = get_angleval(dihedral_list[dihedral][index1],dihedral_list[dihedral][index2],dihedral_list[dihedral][index3],angletypelist,anglevallist) 216 | angleval2 = get_angleval(dihedral_list[dihedral][index2],dihedral_list[dihedral][index3],dihedral_list[dihedral][index4],angletypelist,anglevallist) 217 | 218 | dihedral_feature += (dihedral_angles[dihedral],angleval1,angleval2,bondlen1,bondlen2,bondlen3) 219 | labels.append(dihedral_feature) 220 | return labels 221 | --------------------------------------------------------------------------------