# coding: utf-8 from ase import Atoms from ase.visualize import view import numpy as np import math # List of tools : """ =================Vector tools================== vector_def(A,B) : returns simply the vector translating A to B vector_norm(V) : return euclidian norm of a vector vector_trslt(P,V) : return image of translation of P from vector V throw_away (P,O,d) : returns P' so as O,P and P' are aligned, and OP'=d. So it translate P from O with distance d to direction OP angle_vector(u,v) : returns the value of the convex angle defined by vectors u and v, in radians. ColinearTest(u,v) : returns 1 if u and v colinear, and 0 if not. ===========Distance and Proximity tools======== distance(a,b) : calculate distance between 2 points search_nearest(point,set,d) : search the point in set wich is the nearest from point. We must know that the min distance is d point_set_proximity(point, set) : returns the min distance between the point and the set of points set_set_proximity(S1,S2) : returns minimal distance between each points of each sets. longest_dist(set) : returns the longest distance between the points in the set shortest_dist(set) : returns the shortest distance between the points in the set dist_point_plan(Pt,Plan) : From Pt=[x,y,z] and Plan=[a,b,c,d], return distance beetween Pt and Plan ===============Construction tools=============== Isobarycenter(set) : Calculate isobarycenter of a set of points. Returns his coordinates Invert_Coord(set,O,r) : Apply circular inversion to every point in the set, excepted for origin, remaining origin. Midpoint(P1,P2) : Computes the middle point of P1 and P2 rot3D(P,A,u) : Returns P' image of P by rotation from angle A around unity vector u ===================Data tools=================== commonlist(L1,L2) : Returns a list of elements common to L1 and L2, ie output is L1 intercection with L2 cleanlist(list) : Returns a list without repeated elements (each element in cleaned list appears only once) """ # ========================Vector Tools============================= def vector_def(A, B): # returns simply the vector translating A to B l = len(A) if l != len(B): print("Major Error : The 2 given points aren't same dimensioned :\nA = {}\nB={}".format(A, B)) V = [] for i in range(0, l): V.append(B[i] - A[i]) return V # ========================================== def vector_norm(V): # return euclidian norm of a vector l = (len(V)) Origin = np.ndarray.tolist(np.zeros(l)) return distance(V, Origin) # ========================================== def vector_trslt(P, V): x, y, z = P a, b, c = V return [x + a, y + b, z + c] # ========================================== def throw_away(P, O, d): # returns P' so as O,P and P' are aligned, and OP'=d. So it translate P from O with distance d to direction OP OP = tool.vector_def(O, P) OP = np.ndarray.tolist(np.multiply(OP, 1. / tool.vector_norm(OP))) output = np.ndarray.tolist(np.multiply(OP, d)) return output # ========================================== def angle_vector(u, v): # returns the value in radian of the convex angle defined by vectors u and v. U = vector_norm(u) V = vector_norm(v) UV = np.dot(u, v) # print("U : {}\nV : {}\n u.v : {}".format(U,U,UV,)) if UV == 0: # print("u.v = 0, on a donc un angle de {}, soit {}°".format(math.pi/2,math.pi/2*180/math.pi)) return math.pi / 2 else: # print("L'angle est donc donc arccos({}) = {} = {}°".format(UV / (U * V),np.arccos(UV/(U*V)),np.arccos(UV/(U*V))*180/math.pi)) return np.arccos(UV / (U * V)) # ========================================== def ColinearTest(u, v): # Tests if u and v colinear L = len(u) k = 999999999999 # initial value, to be sure first ktest will become k if L != len(v): print( "Error : u and v ant same dimension : \nu={}\nv={}\nSo we return u and v not aligned... but verify consequences".format( u, v)) else: for i in range(0, L): if u[i] == 0 or v[i] == 0: if u[i] != 0 or v[i] != 0: return 1 else: ktest = u[i] / v[i] if k == 999999999999: k = ktest elif np.abs(k - ktest) < 0.0000001: # We accept almost colinearité at 1/10^6 return 1 return 0 # ========================================== # ========================================== # ========================================== # ==============Distance and Proximity Tools======================= def distance(a, b): # Calculate distance between 2 points d = 0.0 dim = len(a) for i in range(0, dim): d += (b[i] - a[i]) ** 2 d = np.sqrt(d) return d # ========================================== def search_nearest(point, set, d): # search the point in set wich is the nearest from point. We must know that the min distance is d for p in set: if distance(point, p) == d: return p # ========================================== # ========================================== def point_set_proximity(point, set): # returns the min distance between the point and the set of points d = distance(point, set[0]) for p in set[1:]: d = min(d, distance(point, p)) return d # ========================================== def set_set_proximity(S1, S2): # returns minimal distance between each points of each sets. d = point_set_proximity(S1[0], S2) for s in S1[1:]: d = min(d, point_set_proximity(s, S2)) return d # ========================================== def longest_dist(set): # returns the longest distance between the points in the set L = len(set) if L < 2: print("Major ERROR : the set has become a 1-UPLET") quit() else: d = distance(set[L - 2], set[L - 1]) # The last ones for i in range(0, L - 2): for j in range(i + 1, L - 2): d = max(d, distance(set[i], set[j])) return d # ========================================== def shortest_dist(set): # returns the shortest distance between the points in the set L = len(set) if L < 2: print("Major ERROR : the set has become a 1-UPLET") quit() else: d = distance(set[L - 2], set[L - 1]) # The last ones for i in range(0, L - 2): for j in range(i + 1, L - 2): d = min(d, distance(set[i], set[j])) return d # ========================================== def dist_point_plan(Pt, Plan): # From Pt=[x,y,z] and Plan=[a,b,c,d] corresponding to plan's equation ax + by + cz + d = 0, give the distance beetween Pt and the Plan x, y, z = Pt a, b, c, d = Plan dist = np.abs(a * x + b * y + c * z + d) / np.sqrt(a ** 2 + b ** 2 + c ** 2) return dist # ======================Construction tools========================= def Isobarycenter(set): # Calculate isobarycenter of a set of points. Returns his coordinates x = y = z = 0.0 l = len(set) for point in set: x += point[0] / l y += point[1] / l z += point[2] / l # print("New Centroid of cluter:",[x,y,z]) return [x, y, z] # ========================================== def Invert_Coord(set, O, r): # Apply circular inversion to every point in the set, excepted for origin, remaining origin. output = [] for point in set: if point == O: output.append(point) else: D = distance(O, point) OP = vector_def(O, point) OP = np.multiply(OP, 1. / D) # set OP to unity vector add = np.ndarray.tolist(np.array(O) + np.multiply(OP, r ** 2 / D)) output.append(add) return output # ========================================== def Midpoint(P1, P2): # From points coordinates P1 and P2 : construct the middle point of [P1,P2] output = np.ndarray.tolist(np.multiply((np.array(P1) + np.array(P2)), 0.5)) return output # ========================================== def rot3D(P, A, u): # Verify first if u is unity vector : if vector_norm(u) != 1: u = np.ndarray.tolist(np.multiply(u, 1. / vector_norm(u))) # From P in R3, A in R and u in R3, returns the image from P's rotation around u from angle A x, y, z = P ux, uy, uz = u c = np.cos(A) s = np.sin(A) # We compute directly the result : see the 3D rotation matrix X = x * (ux ** 2 * (1 - c) + c) + y * (ux * uy * (1 - c) - uz * s) + z * (ux * uz * (1 - c) + uy * s) Y = x * (ux * uy * (1 - c) + uz * s) + y * (uy ** 2 * (1 - c) + c) + z * (uy * uz * (1 - c) - ux * s) Z = x * (ux * uz * (1 - c) - uy * s) + y * (uy * uz * (1 - c) + ux * s) + z * (uz ** 2 * (1 - c) + c) return [X, Y, Z] # =========================Data Tools============================== def commonlist(L1, L2): # Returns a list of elements common to L1 and L2, ie output is L1 intercection with L2 output = [] for i in L1: if i in L2: output.append(i) return output # ========================================== def cleanlist(list): # Returns a list without repeated elements (each element in cleaned list appears only once) ls = len(list) Index = range(ls) Output = [] for iS in range(ls): if iS in Index: for iOS in range(iS + 1, ls): S = list[iS] OS = list[iOS] if S == OS: Index.remove(iOS) # S and OS are same coord or almost : we remove the last : OS # else : iS correspond to coord needed to be deleted, so we don't add it for I in Index: Output.append(list[I]) return Output # ==========================================