import numpy as np
from fractions import gcd
import integer_manipulations as int_man
import find_csl_dsc as fcd
import sys
import os
file_dir = os.path.dirname(os.path.realpath(__file__))
# Load the following modules from tools directory
path_dir1 = file_dir + '/tools/'
sys.path.append(path_dir1)
import Col
import lll_reduction as lll_red
import smith_nf as snf
# -----------------------------------------------------------------------------------------------------------
[docs]def check_int_mats(l1, l2):
"""
The function checks whether or not the elements of
$A_{left}^{-1}$*B are integers
Parameters
----------
l1, l2 : numpy arrays of same dimensions
Returns
-------
cond: numpy boolean array
"""
l1_linv = np.dot(np.linalg.inv(np.dot(l1.T, l1)), l1.T)
cond = int_man.int_check(np.dot(l1_linv, l2), 10)
return cond
# -----------------------------------------------------------------------------------------------------------
[docs]def check_2d_csl(l_pl1_g1, l_pl2_g1, l_csl_g1):
"""
The function checks whether or not the CSL basis may be expressed
as a linear integer combination of the plane bases of planes 1 and 2
Parameters
----------------
l_pl1_g1, l_pl2_g1: numpy arrays of basis vectors for plane 1 and 2
in the g1 reference frame
"""
ct = 1
str1 = 'Check ' + str(ct) + ' : --> '
if check_int_mats(l_pl1_g1, l_csl_g1).all():
str2 = 'YES\n'
color = 'yel'
else:
raise Exception('The 2D CSL does not contain base1.')
print str1,
txt = Col()
txt.c_prnt(str2, color)
# --------------------------
ct += 1
str1 = 'Check ' + str(ct) + ' : --> '
if check_int_mats(l_pl2_g1, l_csl_g1).all():
str2 = 'YES\n'
color = 'yel'
else:
raise Exception('The 2D CSL does not contain base2.')
print str1,
txt = Col()
txt.c_prnt(str2, color)
# -----------------------------------------------------------------------------------------------------------
[docs]def lbi_dioph_soln(a, b, c):
"""
Computes the diophantaine solution for the equation ax + by = c
"""
k = abs(gcd(a, b))
if np.fmod(c, k) != 0.0:
raise Exception('No Solutions Exist')
mult = c / k
# b1 = extended_euclid(a, b) ####<----------------- must be verified
b1 = np.zeros(2)
b1[0], b1[1], _ = snf.extgcd(a, b)
x1 = mult * b1[0]
x2 = mult * b1[1]
if a*x1 + b*x2 - c != 0:
raise Exception('Something wrong with the Algorithm')
tk = -(b-a)/(a**2 + b**2)
tk_mat = np.array([[np.ceil(tk)], [np.floor(tk)]])
x_sol = np.array([[x1], [x1]]) + tk_mat * b
y_sol = np.array([[x2], [x2]]) - tk_mat * a
sol_mag = np.power(x_sol, 2) + np.power(y_sol, 2)
ind = np.where(sol_mag == min(sol_mag))[0]
int_soln = [x_sol[ind[0]], y_sol[ind[0]]]
return int_soln
# -----------------------------------------------------------------------------------------------------------
[docs]def compute_basis_vec(d_eq):
"""
The function computes y1, y2, y3 such that h\*y1 + k\*y2 + l\*y3 = 0
and modulus of y1 is a minimum
Parameters
-----------------
d_eq: numpy array or list of size 3 and dimension 1
h = d_eq[0], k = d_eq[1], l = d_eq[2]
Returns
------------
np.array([y1, y2, y3])
"""
hp = d_eq[0]
kp = d_eq[1]
lp = d_eq[2]
# Find the minimum y1 such that y2 and y3 are solutions of the equation.
# kp*y2 + lp*y3 = -hp*y1 (Diaphontane Equation).
# Solutions exist if gcd(kp,lp) is a multiple of hp*y1
cond = 0
y1 = 1
while cond == 0:
if np.fmod(hp * y1, gcd(kp, lp)) == 0:
cond = 1
else:
y1 += 1
# Diophantine Equation: ax + by = c
# To solve: f = kp*x + lp*y + hp*m = 0;
avar = kp
bvar = lp
cvar = -hp * y1
int_soln = lbi_dioph_soln(avar, bvar, cvar)
y2 = int_soln[0]
y3 = int_soln[1]
if (kp*y2 + lp*y3 + hp*y1) != 0:
raise Exception('Error with Diophantine solution')
return np.array([y1, y2, y3])
# -----------------------------------------------------------------------------------------------------------
[docs]def bp_basis(bp_g1, lattice):
"""
The function computes the primitve basis of the plane if the
boundary plane normal and the underlying lattice are specified
Parameters
---------------
bp_g1: numpy array
Boundary plane normal in 'g1' reference frame
lattice: Lattice class
Attributes of the under lattice
Returns
-----------
l_pl_g1: numpy array
The primitive basis of the plane with boundary plane normal bp_g1
"""
l_g1_go1 = lattice.l_g_go
# Metric Tensor $G = S^T S$
g_g1 = np.dot(l_g1_go1.T, l_g1_go1)
rat_tols = np.array([1e-05, 1e-06, 1e-07, 1e-08, 1e-09, 1e-10])
d_eq = np.zeros((len(rat_tols), 3))
d_eq_norms = np.zeros((len(rat_tols), 1))
for i in range(len(rat_tols)):
d_eq[i, :] = int_man.int_finder(np.dot(bp_g1.T, g_g1), rat_tols[i])
d_eq_norms[i] = np.sqrt(np.dot(d_eq[i, :], d_eq[i, :].T))
# Add repeatablity of the numerator
t_ind = np.where(d_eq_norms == min(d_eq_norms))
hp = d_eq[t_ind[0][0], 0]
kp = d_eq[t_ind[0][0], 1]
lp = d_eq[t_ind[0][0], 2]
if hp == 0 and kp == 0 and lp == 0:
raise Exception('hkl indices cannot all be zero')
else:
if hp != 0 and kp != 0 and lp != 0:
gc_f1_p = gcd(kp, lp)
bv1_g1 = np.array([[0], [-lp / gc_f1_p], [kp / gc_f1_p]])
bv2_g1 = compute_basis_vec([hp, kp, lp])
else:
if hp == 0:
if kp == 0:
bv1_g1 = np.array([[1], [1], [0]])
bv2_g1 = np.array([[1], [-1], [0]])
elif lp == 0:
bv1_g1 = np.array([[1], [0], [1]])
bv2_g1 = np.array([[1], [0], [-1]])
else:
gc_f1_p = gcd(kp, lp)
bv1_g1 = np.array([[0], [-lp / gc_f1_p],
[kp / gc_f1_p]])
bv2_g1 = compute_basis_vec([hp, kp, lp])
else:
if kp == 0:
if lp == 0:
bv1_g1 = np.array([[0], [1], [1]])
bv2_g1 = np.array([[0], [1], [-1]])
else:
gc_f1_p = gcd(hp, lp)
bv1_g1 = np.array([[-lp / gc_f1_p], [0],
[hp / gc_f1_p]])
bv2_g1 = np.array([[-lp / gc_f1_p], [1],
[hp / gc_f1_p]])
else:
if lp == 0:
gc_f1_p = gcd(hp, kp)
bv1_g1 = np.array([[-kp / gc_f1_p],
[hp / gc_f1_p], [0]])
bv2_g1 = np.array([[-kp / gc_f1_p],
[hp / gc_f1_p], [1]])
# The reduced basis vectors for the plane
l_pl_g1 = lll_red.lll_reduction(np.column_stack([bv1_g1, bv2_g1]))
return l_pl_g1
# -----------------------------------------------------------------------------------------------------------
[docs]def pl_density(l_pl_g1, l_g1_go1):
"""
For a given two-dimensional plane basis, the planar density is
computed
Parameters
---------------
l_pl_g1: numpy array
l_g1_go1: numpy array
Basis vectors of the underlying lattice with respect to the
orthogonal reference frame 'go1'
Returns
----------
pd: float
Planar density = (1/area covered by plane basis)
"""
l_pl_go1 = np.dot(l_g1_go1, l_pl_g1)
planar_basis_area = np.linalg.norm(np.cross(l_pl_go1[:, 0],
l_pl_go1[:, 1]))
pd = 1.0/planar_basis_area
return pd
# -----------------------------------------------------------------------------------------------------------
[docs]def csl_finder_2d(l_pl1_g1, l_pl2_g1):
"""
Given two plane bases, the 2D CSL bases are obtined by utilizing the
smith normal form of the transformation between the two bases
Parameters
---------------
l_pl1_g1, l_pl2_g1: numpy array
Basis vectors of planes 1 and 2 expressed in g1 reference frame
Returns
---------------
l_2d_csl_g1: numpy array
The basis vectors of the 2D CSL expressed in g1 reference frame
"""
l1 = np.array(l_pl1_g1)
l2 = np.array(l_pl2_g1)
# L2 = L1*T (T := T_Pl1ToPl2_Pl1)
l1_linv = np.dot(np.linalg.inv(np.dot(l1.T, l1)), l1.T)
t = np.dot(l1_linv, l2)
# # Obtain N1 and N2
n1, a = int_man.int_mult(t)
if int_man.int_check(a, 12).all:
a = np.around(a)
# A = U*E*V'; E is a diagonal matrix
u, e, v = snf.smith_nf(a)
l2_n = np.dot(l2, np.linalg.inv(v.T))
l_2d_csl_g1 = fcd.cls_elem_div_thm_l2(e/n1, l2_n)
if int_man.int_check(l_2d_csl_g1, 10).all():
l_2d_csl_g1 = np.around(l_2d_csl_g1)
else:
raise Exception('Wrong CSL computation')
l_2d_csl_g1 = lll_red.lll_reduction(l_2d_csl_g1[:, 0:2])
return l_2d_csl_g1
# -----------------------------------------------------------------------------------------------------------
[docs]def gb_2d_csl(bp1_g1, t_g1tog2_g1, lattice):
"""
For a given boundary plane normal 'bp1_g1' and the misorientation
matrix 't_g1tog2_g1', the two-dimensional CSL lattice is computed
Parameters
---------------
bp1_g1: numpy array
t_g1tog2_g1: numpy array
lattice: Lattice class
Returns
-----------
l_2d_csl_g1: numpy array
The basis vectors of the 2D CSL expressed in g1 reference frame
l_pl1_g1, l_pl2_g1: numpy arrays
Basis vectors of planes 1 and 2 expressed in g1 reference frame
"""
l_g1_go1 = lattice.l_g_go
bp1_go1 = np.dot(l_g1_go1, bp1_g1)
l_g2_g1 = t_g1tog2_g1
l_g2_go1 = np.dot(l_g1_go1, l_g2_g1)
l_go1_g2 = np.linalg.inv(l_g2_go1)
bp2_g2 = int_man.int_finder(np.dot(-l_go1_g2, bp1_go1))
l_pl1_g1 = bp_basis(bp1_g1, lattice)
l_pl2_g2 = bp_basis(bp2_g2, lattice)
l_pl2_g1 = np.dot(l_g2_g1, l_pl2_g2)
l_2d_csl_g1 = csl_finder_2d(l_pl1_g1, l_pl2_g1)
return l_2d_csl_g1, l_pl1_g1, l_pl2_g1
# -----------------------------------------------------------------------------------------------------------
[docs]def bicryst_planar_den(bp1_go1, t_g1tog2_go1, lattice):
"""
The function computes the planar densities of the planes
1 and 2 and the two-dimensional CSL
Parameters
---------------
bp1_go1: numpy array
The boundary plane normal components in go1 reference frame
t_g1tog2_go1: numpy array
Transformation matrix from g1 to g2 in go1 reference frame
lattice: Lattice class
Attributes of the underlying lattice
Returns
-----------
pl_den_pl1, pl_den_pl2: numpy array
The planar density of planes 1 and 2
pl_den_csl: numpy array
The planare density of the two-dimensional CSL
"""
l_g1_go1 = lattice.l_g_go
l_go1_g1 = np.linalg.inv(l_g1_go1)
bp1_g1 = np.dot(l_go1_g1, bp1_go1)
t_g1tog2_g1 = np.dot(l_go1_g1, np.dot(t_g1tog2_go1, l_g1_go1))
l_2d_csl_g1, l_pl1_g1, l_pl2_g1 = gb_2d_csl(bp1_g1, t_g1tog2_g1, lattice)
check_2d_csl(l_pl1_g1, l_pl2_g1, l_2d_csl_g1)
pl_den_pl1 = pl_density(l_pl1_g1, l_g1_go1)
pl_den_pl2 = pl_density(l_pl2_g1, l_g1_go1)
pl_den_csl = pl_density(l_2d_csl_g1, l_g1_go1)
return pl_den_pl1, pl_den_pl2, pl_den_csl
# -----------------------------------------------------------------------------------------------------------