# Path: siman/geo.py
# def image_distance(x1, x2, r, order = 1, sort_flag = True, return_n_distances = False, coord_type = 'xcart'):
#     """
#     Calculate smallest distance and the next smallest distance between two atoms 
#     correctly treating periodic boundary conditions and oblique cells.
#     x1, x2 - vector[3] xcart coordinates of two atoms
#     r - rprimd of cell
#     order - the order of periodic images which are accounted in the calcualtion of distances between atoms.
#     for cubic cells, order = 1 always provide correct result.
#     For highly oblique cell you should test and find the needed value of 'order' after which results are the same.
#     sort_flag (bool) - use False if you do not need sorting of distances 
# 
#     return_n_distances(bool) - returns required number of smallest distances, depending on order
# 
#     coord_type (str) 
#         - 'xred'
#         - 'xcart'
# 
# 
#     return d1, d2 - the smallest and next smallest distances between atoms
# 
#     """
#     d = [] # list of distances between 1st atom and images of 2nd atom
#     
#     if coord_type == 'xcart':
#         def dr(i,j,k):
#             return (r[0] * i + r[1] * j + r[2] * k)
#     if coord_type == 'xred':
#         a1=np.array([1,0,0])
#         a2=np.array([0,1,0])
#         a3=np.array([0,0,1])
#         def dr(i,j,k):
#             return (a1 * i + a2 * j + a3 * k)
# 
#     for i in range(-order, order+1):
#         for j in range(-order, order+1):
#             for k in range(-order, order+1):
#                 x2i = x2 +  dr(i,j,k) #determine coordinates of image of atom 2 in corresponding image cells
#                 d.append(   np.linalg.norm(x1 - x2i)   )
#     
#     if sort_flag:
#         d.sort()
#     #print d
#     # assert d[0] == min(d)
# 
#     if return_n_distances:
#         return d[0:return_n_distances]
#     else:
#         return d[0], d[1] # old behaviour


import os, copy, shutil, sys
import numpy as np
from siman.geo import image_distance
# -*- coding: utf-8 -*- 
#Copyright Aksyonov D.A
"""
module contains different calculators of energy, etc.
"""
from __future__ import division, unicode_literals, absolute_import 


def buck(r, el1, el2):
    #Repulsive energy according to Kunz1992
    A = {'Li':1.061, 'Na':1.432, 'K':1.794, 'Fe':1.335, 'V':1.276, 'Mn':1.366, 'O':1.853, 'F':1.492, 'P':0.887} # +2 oxidation states for metals (small diff from +3)
    B = {'Li':0.07, 'Na':0.082, 'K':0.11, 'Fe':0.066, 'V':0.086, 'Mn':0.066, 'O':0.168, 'F':0.133, 'P':0.017}

    kcal_mol2eV = 4.3363e-2 
    if r > 0.001:
        E = kcal_mol2eV* (B[el1]+B[el2]) * np.exp( (A[el1] + A[el2] - r)/ (B[el1] +B[el2])   )
    else:
        E = 0
    return E

def site_repulsive_e(st, i):
    """
    calculate repulsive energy for site i of structure st
    """

    xc = st.xcart[i]
    el = st.get_elements()
    E = 0
    for j, x in enumerate(st.xcart):

# Path: siman/geo.py
# def image_distance(x1, x2, r, order = 1, sort_flag = True, return_n_distances = False, coord_type = 'xcart'):
#     """
#     Calculate smallest distance and the next smallest distance between two atoms 
#     correctly treating periodic boundary conditions and oblique cells.
#     x1, x2 - vector[3] xcart coordinates of two atoms
#     r - rprimd of cell
#     order - the order of periodic images which are accounted in the calcualtion of distances between atoms.
#     for cubic cells, order = 1 always provide correct result.
#     For highly oblique cell you should test and find the needed value of 'order' after which results are the same.
#     sort_flag (bool) - use False if you do not need sorting of distances 
# 
#     return_n_distances(bool) - returns required number of smallest distances, depending on order
# 
#     coord_type (str) 
#         - 'xred'
#         - 'xcart'
# 
# 
#     return d1, d2 - the smallest and next smallest distances between atoms
# 
#     """
#     d = [] # list of distances between 1st atom and images of 2nd atom
#     
#     if coord_type == 'xcart':
#         def dr(i,j,k):
#             return (r[0] * i + r[1] * j + r[2] * k)
#     if coord_type == 'xred':
#         a1=np.array([1,0,0])
#         a2=np.array([0,1,0])
#         a3=np.array([0,0,1])
#         def dr(i,j,k):
#             return (a1 * i + a2 * j + a3 * k)
# 
#     for i in range(-order, order+1):
#         for j in range(-order, order+1):
#             for k in range(-order, order+1):
#                 x2i = x2 +  dr(i,j,k) #determine coordinates of image of atom 2 in corresponding image cells
#                 d.append(   np.linalg.norm(x1 - x2i)   )
#     
#     if sort_flag:
#         d.sort()
#     #print d
#     # assert d[0] == min(d)
# 
#     if return_n_distances:
#         return d[0:return_n_distances]
#     else:
#         return d[0], d[1] # old behaviour


# Path: siman/calcul.py
import os, copy, shutil, sys
import numpy as np
from siman.geo import image_distance

# -*- coding: utf-8 -*- 
#Copyright Aksyonov D.A
"""
module contains different calculators of energy, etc.
"""
from __future__ import division, unicode_literals, absolute_import 


def buck(r, el1, el2):
    #Repulsive energy according to Kunz1992
    A = {'Li':1.061, 'Na':1.432, 'K':1.794, 'Fe':1.335, 'V':1.276, 'Mn':1.366, 'O':1.853, 'F':1.492, 'P':0.887} # +2 oxidation states for metals (small diff from +3)
    B = {'Li':0.07, 'Na':0.082, 'K':0.11, 'Fe':0.066, 'V':0.086, 'Mn':0.066, 'O':0.168, 'F':0.133, 'P':0.017}

    kcal_mol2eV = 4.3363e-2 
    if r > 0.001:
        E = kcal_mol2eV* (B[el1]+B[el2]) * np.exp( (A[el1] + A[el2] - r)/ (B[el1] +B[el2])   )
    else:
        E = 0
    return E

def site_repulsive_e(st, i):
    """
    calculate repulsive energy for site i of structure st
    """

    xc = st.xcart[i]
    el = st.get_elements()
    E = 0
    for j, x in enumerate(st.xcart):

        d = image_distance(xc, x, st.rprimd)[0]