Andrei tomut
big grid
a117bb5
raw
history blame
No virus
5.57 kB
import numpy as np
import copy
from scipy import optimize
from .geometry import ChangeBasis, supercell_points, get_supercell_vectors
class LatMatch:
opt_angle = True
opt_strain = True
# theta_min= 15*np.pi/180
theta_min = 5 * np.pi / 180
theta_range = (-np.pi / 2, np.pi / 2)
smax = [0.1, 0.1]
bounds = None
result = None
def __init__(self, scdim, reference, target, optimize_angle=True, optimize_strain=True):
self.ref = reference
self.tar = target
self.dim = scdim
self.updated_target_cell = None
self.sc_vec = None
self.opt_angle = optimize_angle
self.opt_strain = optimize_strain
self.result=None
def setMaxStrain(self, s):
try:
s0, s1 = np.array(s)
self.smax = s0, s1
except:
try:
self.smax = [float(s)]
except:
print("The max strain value:", s, "is not valid")
return None;
def setMinAngle(self, theta_min):
self.theta_min = theta_min
return None
def optimizeAngle(self, opt):
self.opt_angle = opt
def optimizeStrain(self, opt):
self.opt_strain = opt
def costFuncion(self, r, eta=0.001):
dx, dy = (r - np.floor(r))
cost = 0
etac = np.sqrt(2) * eta
n = int(np.ceil(eta))
for (nx, ny) in np.mgrid[-n:n, -n:n].T.reshape(n ** 2 * 4, 2):
# print("nx:",nx)
# print("ny:", ny)
# print("dx:", dx)
# print("dy:", dy)
# print("etc:", etac)
d2 = (dx + nx) ** 2 + (dy + ny) ** 2
cost += np.mean(np.exp(- d2 / (2 * etac))) / n ** 2
return -cost
def fitness(self, x):
s1, s2, theta = 0.0, 0.0, 0.0
if (len(x) == 3):
s1, s2, theta = x
if (len(x) == 2):
s1, s2 = x
if (len(x) == 1):
if not self.opt_angle:
s1 = s2 = float(x)
else:
theta = float(x)
Bsc_points = supercell_points(self.dim, Smat(s1, s2) @ Rmat(theta) @ self.tar)
rBinA = ChangeBasis(Bsc_points, self.ref)
return self.costFuncion(rBinA)
def supercellVectors(self, force=False):
if self.sc_vec is not None and not force:
return self.sc_vec
# Catch the proper variables. This should be properly improved
if not self.opt_strain:
self.bounds = [(self.theta_range[0], self.theta_range[1])]
elif not self.opt_angle:
smax = self.smax
if (len(smax) == 1):
self.bounds = [(-smax[0], smax[0])]
print(self.bounds)
else:
self.bounds = [(-smax[0], smax[0]), (-smax[1], smax[1])]
else:
smax = self.smax
self.bounds = [(-smax[0], smax[0]), (-smax[1], smax[1]), (self.theta_range[0], self.theta_range[1])]
print("cost without otimization", self.fitness([0, 0, 0]))
res = optimize.differential_evolution(self.fitness, self.bounds, maxiter=1000, popsize=1000, polish=True)
# Catch the proper variables. This should be properly improved
s1, s2, theta = 0, 0, 0
if not self.opt_strain:
theta = float(res.x)
elif not self.opt_angle:
if (len(smax) == 1):
s1, s2 = float(res.x), float(res.x)
else:
s1, s2 = res.x
else:
s1, s2, theta = res.x
self.result = (s1, s2, theta)
print("result:", self.result )
print("cost after otimization", self.fitness([s1, s2, theta]))
self.updated_target_cell = Smat(s1, s2) @ Rmat(theta) @ self.tar
return get_supercell_vectors(self.dim, self.updated_target_cell, self.ref)
def updatedCell(self):
return self.updated_target_cell
def supercell(self, force=False):
L = self.supercellVectors(force=force)
try:
L = L.T
N = np.linalg.norm(L, axis=1)
idx = np.argsort(N)
L = L[idx][1:]
N = N[idx][1:]
except:
print(" Not enough supercell vectors to construct a basis", L)
thetas = np.diag(1 / N) @ L
thetas = thetas @ (thetas.T)
print(thetas)
good_thetas = np.abs(thetas) < np.cos(self.theta_min)
iop, jop, min = 0, 0, 1e14;
for i, row in enumerate(good_thetas):
for j, good_angle in enumerate(row):
pair_norm = N[i] ** 2 + N[j] ** 2 + np.abs(np.cross(L[i], L[j]))
# pair_norm = np.abs(np.cross(L[i],L[j]));
if (good_angle and pair_norm < min):
min = pair_norm
iop, jop = i, j
sc_vec = np.transpose([L[iop], L[jop]])
return sc_vec
def get_optimized_target(self, Blat3D,Batoms3D ):
"""
:param Blat3D: B lattice
:param Batoms3D: B atoms
:return:
"""
s1, s2, theta = self.Result()
Tr = np.eye(3)
Tr[:2, :2] = SR(s1, s2, theta)
oBlat3D = copy.copy(Blat3D)
oBlat3D = (Tr @ (oBlat3D.T)).T
s, rs = list(zip(*Batoms3D))
rs = [Tr @ r for r in rs]
oBatoms3D = list(zip(s, rs))
return oBlat3D, oBatoms3D
def Rmat(theta):
return np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
def Smat(s1, s2):
return np.diag([1 + s1, 1 + s2])
def SR(s1, s2, theta):
return Smat(s1, s2) @ Rmat(theta)