Commit 5015902e authored by Malthe Kjær Bisbo's avatar Malthe Kjær Bisbo
Browse files

slight changes to descriptors and prior

parent dd3edadb
import os
import sys
import numpy as np
from math import erf
from itertools import product
from scipy.spatial.distance import cdist
try:
cwd = sys.argv[1]
except:
cwd = os.getcwd()
class Angular_Fingerprint(object):
""" comparator for construction of angular fingerprints
"""
def __init__(self, atoms, Rc1=4.0, Rc2=4.0, binwidth1=0.1, Nbins2=30, sigma1=0.2, sigma2=0.10, nsigma=4, eta=1, gamma=3, use_angular=True):
""" Set a common cut of radius
"""
self.Rc1 = Rc1
self.Rc2 = Rc2
self.binwidth1 = binwidth1
self.Nbins2 = Nbins2
self.binwidth2 = np.pi / Nbins2
self.sigma1 = sigma1
self.sigma2 = sigma2
self.nsigma = nsigma
self.eta = eta
self.gamma = gamma
self.use_angular = use_angular
self.pbc = atoms.get_pbc()
self.cell = atoms.get_cell()
self.n_atoms = atoms.get_number_of_atoms()
self.num = atoms.get_atomic_numbers()
self.atomic_types = sorted(list(set(self.num)))
self.atomic_count = {type:list(self.num).count(type) for type in self.atomic_types}
self.volume = atoms.get_volume()
self.dim = 3
# parameters for the binning:
self.m1 = self.nsigma*self.sigma1/self.binwidth1 # number of neighbour bins included.
self.smearing_norm1 = erf(1/np.sqrt(2) * self.m1 * self.binwidth1/self.sigma1) # Integral of the included part of the gauss
self.Nbins1 = int(np.ceil(self.Rc1/self.binwidth1))
self.m2 = self.nsigma*self.sigma2/self.binwidth2 # number of neighbour bins included.
self.smearing_norm2 = erf(1/np.sqrt(2) * self.m2 * self.binwidth2/self.sigma2) # Integral of the included part of the gauss
self.binwidth2 = np.pi/Nbins2
Nelements_2body = self.Nbins1
Nelements_3body = self.Nbins2
if use_angular:
self.Nelements = Nelements_2body + Nelements_3body
else:
self.Nelements = Nelements_2body
def get_feature(self, atoms):
"""
"""
cell = self.cell
n_atoms = self.n_atoms
pos = atoms.get_positions().tolist()
num = atoms.get_atomic_numbers()
atomic_count = self.atomic_count
return pos
def __angle(self, vec1, vec2):
"""
Returns angle with convention [0,pi]
"""
norm1 = np.linalg.norm(vec1)
norm2 = np.linalg.norm(vec2)
arg = np.dot(vec1,vec2)/(norm1*norm2)
# This is added to correct for numerical errors
if arg < -1:
arg = -1.
elif arg > 1:
arg = 1.
return np.arccos(arg), arg
def __f_cutoff(self, r, gamma, Rc):
"""
Polinomial cutoff function in the, with the steepness determined by "gamma"
gamma = 2 resembels the cosine cutoff function.
For large gamma, the function goes towards a step function at Rc.
"""
if not gamma == 0:
return 1 + gamma*(r/Rc)**(gamma+1) - (gamma+1)*(r/Rc)**gamma
else:
return 1
def __f_cutoff_grad(self, r, gamma, Rc):
if not gamma == 0:
return gamma*(gamma+1)/Rc * ((r/Rc)**gamma - (r/Rc)**(gamma-1))
else:
return 0
def angle2_grad(self, RijVec, RikVec):
Rij = np.linalg.norm(RijVec)
Rik = np.linalg.norm(RikVec)
a = RijVec/Rij - RikVec/Rik
b = RijVec/Rij + RikVec/Rik
A = np.linalg.norm(a)
B = np.linalg.norm(b)
D = A/B
RijMat = np.dot(RijVec[:,np.newaxis], RijVec[:,np.newaxis].T)
RikMat = np.dot(RikVec[:,np.newaxis], RikVec[:,np.newaxis].T)
a_grad_j = -1/Rij**3 * RijMat + 1/Rij * np.identity(3)
b_grad_j = a_grad_j
a_sum_j = np.sum(a*a_grad_j, axis=1)
b_sum_j = np.sum(b*b_grad_j, axis=1)
grad_j = 2/(1+D**2) * (1/(A*B) * a_sum_j - A/(B**3) * b_sum_j)
a_grad_k = 1/Rik**3 * RikMat - 1/Rik * np.identity(3)
b_grad_k = -a_grad_k
a_sum_k = np.sum(a*a_grad_k, axis=1)
b_sum_k = np.sum(b*b_grad_k, axis=1)
grad_k = 2/(1+D**2) * (1/(A*B) * a_sum_k - A/(B**3) * b_sum_k)
a_grad_i = -(a_grad_j + a_grad_k)
b_grad_i = -(b_grad_j + b_grad_k)
a_sum_i = np.sum(a*a_grad_i, axis=1)
b_sum_i = np.sum(b*b_grad_i, axis=1)
grad_i = 2/(1+D**2) * (1/(A*B) * a_sum_i - A/(B**3) * b_sum_i)
return grad_i, grad_j, grad_k
from distutils.core import setup
from Cython.Build import cythonize
import numpy
setup(ext_modules=cythonize('featureCalculators/angular_fingerprintFeature_cy.pyx'), include_dirs=[numpy.get_include()])
import numpy as np
from kernel import gauss_kernel, double_gauss_kernel
from descriptor.fingerprint import Fingerprint
from prior.prior import repulsive_prior
class gpr_memory():
def __init__(self, descriptor, prior):
self.energies = None
self.features = None
self.prior_values = None
self.descriptor = descriptor
self.prior = prior
def save_data(self, atoms_list):
energies_save = np.array([a.get_potential_energy() for a in atoms_list])
self.save_energies(energies_save)
features_save = descriptor.get_featureMat(atoms_list)
self.save_features(features_save)
if self.prior is not None:
prior_values_save = np.array([self.prior.energy(a) for a in atoms_list])
self.save_prior_values(prior_values_save)
def save_energies(self, energies_save):
if self.energies in None:
self.energies = energies_save
else:
self.energies = np.r_[self.energies, energies_save]
def save_features(self, features_save):
if self.features in None:
self.features = features_save
else:
self.features = np.r_[self.features, features_save]
def save_prior_values(self, prior_values_save):
if self.prior_values in None:
self.prior_values = prior_values_save
else:
self.prior_values = np.r_[self.prior_values, prior_values_save]
class gpr():
"""Gaussian Process Regression
......@@ -12,22 +55,37 @@ class gpr():
prior:
"""
def __init__(self, descriptor, kernel, prior):
self.descriptor = descriptor
if kernel is None:
kernel = gauss_kernel()
def __init__(self, descriptor=None, kernel='single', prior=None):
if descriptor is None:
self.descriptor = Fingerprint()
else:
self.descriptor = descriptor
if kernel is 'single':
self.kernel = gauss_kernel()
elif kernel is 'double':
self.kernel = double_gauss_kernel()
else:
self.kernel = kernel
self.prior = prior
if prior is None:
self.prior = repulsive_prior()
else:
self.prior = prior
self.memory = gpr_memory(self.descriptor, self.prior)
def predict(self, a):
x = self.descriptor.get_feature(a)
k = self.kernel.kernel_vector(x, self.X)
f = k.T.dot(self.alpha) + self.bias + delta
def set_bias(self):
self.bias = np.mean(self.memory.energies)
def train(self):
pass
def optimize_hyperparameters(self):
pass
......
This diff is collapsed.
......@@ -44,11 +44,14 @@ def convert_atom_types(num):
num_converted[i] = j
return num_converted
class delta():
class repulsive_prior():
def __init__(self, atoms, rcut=5, ratio_of_covalent_radii=0.7):
def __init__(self, rcut=5, ratio_of_covalent_radii=0.7):
self.rcut = rcut
self.ratio_of_covalent_radii = ratio_of_covalent_radii
self.initialized = False
def initialize_from_atoms(self, atoms):
self.pbc = atoms.get_pbc()
self.cell = atoms.get_cell()
......@@ -59,7 +62,7 @@ class delta():
atomic_types = sorted(list(set(num)))
self.Ntypes = len(atomic_types)
blmin_dict = closest_distances_generator(num, ratio_of_covalent_radii=ratio_of_covalent_radii)
blmin_dict = closest_distances_generator(num, ratio_of_covalent_radii=self.ratio_of_covalent_radii)
self.blmin = -np.ones((self.Ntypes, self.Ntypes))
for i1, type1 in enumerate(atomic_types):
......@@ -67,7 +70,11 @@ class delta():
self.blmin[i1,i2] = blmin_dict[(type1, type2)]
self.blmin = self.blmin.reshape(-1).tolist()
self.initialized = True
def energy(self, a):
if not self.initialized:
self.initialize_from_atoms(a)
# Memory allocation pool
cdef Pool mem
......@@ -127,6 +134,9 @@ class delta():
return E/2
def forces(self, a):
if not self.initialized:
self.initialize_from_atoms(a)
# Memory allocation pool
cdef Pool mem
mem = Pool()
......
......@@ -2,4 +2,4 @@ from distutils.core import setup
from Cython.Build import cythonize
import numpy
setup(ext_modules=cythonize('delta.pyx'), include_dirs=[numpy.get_include()])
setup(ext_modules=cythonize('prior.pyx'), include_dirs=[numpy.get_include()])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment