msspec_python3/msspec/es/es_mod/empty_spheres.py

712 lines
32 KiB
Python

# coding: utf-8
import unittest
import math
import numpy as np
import delaunay.core as delc
import es_sym_analys as essyma
import es_tools as tool
import es_clustering as esclus
from scipy.spatial import ConvexHull, Voronoi
# ===========
from ase import Atoms
from ase.visualize import view
from ase.data import covalent_radii
# ===================================================================
# List of routines :
"""
=================
ES_AllRadius_Updater(NewES,Structure,[list]) : Update ES_AllRadius global variable with new radius of empty spheres
given as NewES
Voronoi_Vertex(Structure) : Computes Voronoi Vertices of Structure
Delaunay_Tetrahedral_ES(Structure,[minsize],[maxsize],[tol]) : Creates a tetrehedral mesh from the structure,
then returns for each center the perfect sphere going in.
Convex_Hull_Cover(Structure,[es_radius],[tol],[missing]) : Finds the exterior Hull from the set, create triangular
mesh then returns cover coordinates. tol=0 => no fusion
Select_Int_Ext(Centroid,E1,E2,IE) : Clean the Cover, taking only internal or external
Internal_Hull_Cover(Structure,[es_radius],[tol],[missing]) : Finds the interior Hull from the set, create triangular
mesh then returns cover coordinates
Internal_Hull_Centers(set) : Finds the interior Hull from the set, create triangular mesh then returns centers coordinates
ES_Fusion(set, structure, size) : Change the set by clustering spheres near from size to each other. No size given => take shortest
Maintain distances with structure, compared with the ancient set.
Fusion_Overlap(Spheres_Data,tol) : Find Spheres touching each other, and fusions them. Don't return radius : only final coordinates
Flat_Covering(Structure,[R],[tol],[Curved]) : For flat (or almost) set : Searchs major plane, triangulates,
and cover the 2 sides.
Plane_Triangulation(Plane3D,Plane_eq): Return triangulation of a 3D Plane (convert into 2D, uses Delny)
Atom_Radius(Structure,n,list) : Returns radius of n°th atom in Structure (Angstrom). Regroup different radius lists.
Convex_Hull_InterCover(set) : Return list of internal cover using ConvexHull : Different from Delaunay_Intersphere :
made for empty clusters
=================
"""
ES_AllRadius = [] # Global Variable taking all empty spheres radius
# ===================================================================
def ES_AllRadius_Updater(NewES, Structure, list=1):
# Update ES_AllRadius global variable with new radius of empty spheres given as NewES
global ES_AllRadius
StrPos = np.ndarray.tolist(Structure.positions)
for ES in np.ndarray.tolist(NewES.positions):
# print("ES = {}".format(ES))
Tempo = []
for A in StrPos:
# print("A = {}".format(A))
d = tool.distance(ES, A)
Tempo.append(d - Atom_Radius(Structure, StrPos.index(A), list))
ES_AllRadius.append(min(Tempo))
return ES_AllRadius
# ===================================================================
def Voronoi_Vertex(Structure):
# Uses Delaunay triangulation to create a tetrahedral mesh from the set of
# atoms-centers coordinates, then computes each tetrahedron's inerty center
# Returns list of tetrahedrons-centers coordinates
# Be careful on tetrahedralisation done : the cube for example will not be correctly tesselated (6tetrahedrons in)
"""
Triag=delc.Triangulation(set)
tetracenters=[]
for tetra in Triag.indices:
x = y = z = 0.0
for vertex in tetra:
x += set[vertex][0] / 4.0
y += set[vertex][1] / 4.0
z += set[vertex][2] / 4.0
tetracenters.append((x, y, z))
"""
struct = np.ndarray.tolist(Structure.positions)
Vor = Voronoi(struct)
return np.ndarray.tolist(Vor.vertices)
# ===================================================================
def Delaunay_Tetrahedral_ES(Structure, minsize=0, maxsize=999, tol=0.6):
# Uses Delaunay triangulation to create a tetrahedral mesh from the Structure of
# atoms-centers coordinates, then adds empty sphere in each tetrahedron, equidistant to all Atoms
es_data = []
allradius = []
set = Structure.positions
All_Spheres_Data = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
# print All_Spheres_Data
Triag = delc.Triangulation(set)
for tetra in Triag.indices:
Data = []
for vertex in tetra:
Data.append(All_Spheres_Data[vertex])
tetra_es = esclus.Tetrahedron_ES(Data)
if tetra_es == 999:
EV = []
for vertex in tetra:
EV.append(vertex)
print(
"Error by computing tangent solution to tetrahedron {} : delta < 0 for radius determination ".format(EV))
elif tetra_es != 999: # 999 is returned when the problem has no solution due to singular matrix
if tetra_es[1] <= maxsize:
if tetra_es[1] >= minsize:
es_data.append(tetra_es)
# output.append(tetra_es[0])
"""Verify result : ________________
print("E_S created at position {}, in center of tetrahedron {}".format(output[0],tetra))
viewer = [output[-1]]
for vertex in tetra :
d=tool.distance(set[vertex],tetra_es[0])
print("Distance with vertex {} : {}\nAtom radius = {}, ES radius = {}, so the sum is : {}".format(vertex,d,All_Spheres_Data[vertex][1],tetra_es[1],All_Spheres_Data[vertex][1]+tetra_es[1]))
#viewer.append(set[vertex])
#View=Atoms("XC4",positions = viewer)
#view(View)
#raw_input("\nPress Enter to continue ...\n")
#""" # _______________________________
# print "allradius : \n",allradius
output = Fusion_Overlap(es_data, tol)
return output
# ===================================================================
def Convex_Hull_Cover(Structure, radius_es=0, tol=0.6, missing=False, Int_Ext=0):
# Uses ConvexHull to find the triangular Hull from the set, then generate a covering by adding
# an empty sphere on each hull triangle.
# Default tol value is used for Fusion Overlap
# Returns list of cover coordinates
if Int_Ext == 0:
print("Select wich covering you wish :\n0: Internal Cover\n1: External Cover\n2: Both Cover")
CovChoice = input()
Cover_Data = []
set = np.ndarray.tolist(Structure.positions)
if radius_es == 0:
radius_es = input("Please select the radius of empty spheres you desire : ")
hull = ConvexHull(set)
xc = yc = zc = 0
lh = len(hull.vertices)
for hpt in hull.vertices:
xc += set[hpt][0] / lh
yc += set[hpt][1] / lh
zc += set[hpt][2] / lh
Centroid = [xc, yc, zc]
if missing == False: # It means we don't care if some hull points are not implemented because they are in facet
# Computes the centroïd of the hull
AllData = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
for facet in hull.simplices: # hull.simplices contains index of simplices vertex, grouped by 3.
Data = []
for vertex in facet:
Data.append(AllData[vertex])
ES1, ES2 = esclus.Triangle_ES(Data, radius_es)
if ES1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(radius_es, facet))
if ES1 != 666:
ES = Select_Int_Ext(Centroid, ES1, ES2, 1) # Last parameter != 0 => external cover
if tool.distance(Centroid, ES) < 1000000000:
Cover_Data.append([ES, radius_es])
elif missing == True:
Data = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
HullPlane = tool.cleanlist(np.ndarray.tolist(hull.equations))
for HP in HullPlane:
a, b, c, d = HP
HPList = []
HPIndex = []
for pt in set:
x, y, z = pt
if abs(a * x + b * y + c * z + d) < 0.01: # Then pt is in Plane HP
HPList.append(pt)
HPIndex.append(set.index(pt))
Tria = Plane_Triangulation(HPList, HP)
for tria in Tria.indices:
Spheres_data = [Data[HPIndex[tria[0]]], Data[HPIndex[tria[1]]], Data[HPIndex[tria[2]]]]
ES1, ES2 = esclus.Triangle_ES(Spheres_data, radius_es)
if ES1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(radius_es, [HPIndex[tria[0]],
HPIndex[tria[1]],
HPIndex[tria[2]]]))
if ES1 != 666:
# ES = Select_Int_Ext(Centroid, ES1, ES2, 1) # Last parameter != 1 => external cover
# Cover_Data.append([ES, radius_es])
if CovChoice > 1:
Cover_Data.append([ES1, radius_es])
Cover_Data.append([ES2, radius_es])
else:
ES = Select_Int_Ext(Centroid, ES1, ES2, CovChoice) # 1 : external; 0 : internal
Cover_Data.append([ES, radius_es])
"""Verify result : ________________
print("E_S created at position {}, defined on triangle {}".format(ES, facet))
viewer = [ES,ES2]
for vertex in facet:
d = tool.distance(set[vertex], ES)
print("Distance with vertex {} : {}\nAtom radius = {}, ES radius = {}, so the sum is : {}".format(vertex, d,AllData[vertex][1],radius_es,AllData[vertex][1]+radius_es))
viewer.append(set[vertex])
View=Atoms("XH4",positions = viewer)
view(View)
# raw_input("\nPress Enter to continue ...\n")
# """ # _______________________________
# Fusion overlapping spheres
Output = Fusion_Overlap(Cover_Data, tol) # tol at 1% : means fusion if d < (r1 + r2) * 0.01
return Output
# ===================================================================
def Select_Int_Ext(Centroid, E1, E2, IE):
# Returns only internal or external part of cover, using the fact hull is convex : so using his centroid
# IE = 0 : take internal part, IE != 0 : take external part
d1 = tool.distance(Centroid, E1)
d2 = tool.distance(Centroid, E2)
if IE == 0: # Internal part : the closest to centroid
if d1 < d2:
return E1
else: # External part : the farest from centroïd
if d2 < d1:
return E1
# Excepted this 2 double conditions : we have to take E2
return E2
# ===================================================================
def Internal_Hull_Cover(Structure, radius_es=0, tol=0.6, missing=False):
# Uses ConvexHull to find the triangular Hull from the set, then generate a covering by adding
# an empty sphere on each hull triangle.
# Default tol value is used for Fusion Overlap
# Returns list of cover coordinates
Cover_Data = []
set = np.ndarray.tolist(Structure.positions)
if radius_es == 0:
radius_es = input("Please select the radius of empty spheres you desire : ")
hull = ConvexHull(set)
xc = yc = zc = 0
lh = len(hull.vertices)
for hpt in hull.vertices:
xc += set[hpt][0] / lh
yc += set[hpt][1] / lh
zc += set[hpt][2] / lh
Centroid = [xc, yc, zc]
invset = tool.Invert_Coord(set, Centroid, 10)
hull = ConvexHull(invset)
if missing == False: # It means we don't care if some hull points are not implemented because they are in facet
# Computes the centroïd of the hull
AllData = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
for facet in hull.simplices: # hull.simplices contains index of simplices vertex, grouped by 3.
Data = []
for vertex in facet:
Data.append(AllData[vertex])
ES1, ES2 = esclus.Triangle_ES(Data, radius_es)
if ES1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(radius_es, facet))
if ES1 != 666:
ES = Select_Int_Ext(Centroid, ES1, ES2, 0) # Last parameter = 0 => internal cover
Cover_Data.append([ES, radius_es])
elif missing == True:
Data = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
HullPlane = tool.cleanlist(np.ndarray.tolist(hull.equations))
for HP in HullPlane:
a, b, c, d = HP
HPList = []
HPIndex = []
for pt in set:
x, y, z = pt
if abs(a * x + b * y + c * z + d) < 0.01: # Then pt is in Plane HP
HPList.append(pt)
HPIndex.append(set.index(pt))
Tria = Plane_Triangulation(HPList, HP)
for tria in Tria.indices:
Spheres_data = [Data[HPIndex[tria[0]]], Data[HPIndex[tria[1]]], Data[HPIndex[tria[2]]]]
ES1, ES2 = esclus.Triangle_ES(Spheres_data, radius_es)
if ES1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(radius_es, [HPIndex[tria[0]],
HPIndex[tria[1]],
HPIndex[tria[2]]]))
if ES1 != 666:
ES = Select_Int_Ext(Centroid, ES1, ES2, 0) # Last parameter != 0 => internal cover
Cover_Data.append([ES, radius_es])
"""Verify result : ________________
print("E_S created at position {}, defined on triangle {}".format(ES, facet))
viewer = [ES,ES2]
for vertex in facet:
d = tool.distance(set[vertex], ES)
print("Distance with vertex {} : {}\nAtom radius = {}, ES radius = {}, so the sum is : {}".format(vertex, d,AllData[vertex][1],radius_es,AllData[vertex][1]+radius_es))
viewer.append(set[vertex])
View=Atoms("XH4",positions = viewer)
view(View)
# raw_input("\nPress Enter to continue ...\n")
# """ # _______________________________
# Fusion overlapping spheres
Output = Fusion_Overlap(Cover_Data, tol) # tol at 1% : means fusion if d < (r1 + r2) * 0.01
return Output
# ===================================================================
def Internal_Hull_Centers(set):
# Uses ConvexHull to find the intern triangular Hull from the set, then computes all centers of simplices
# Returns list of centers coordinates
invset = tool.Invert_Coord(set, [0, 0, 0], 10)
hull = ConvexHull(invset)
output = []
for facet in hull.simplices:
x = y = z = 0.0
for vertex in facet:
x += set[vertex][0] / 3.0
y += set[vertex][1] / 3.0
z += set[vertex][2] / 3.0
facet_center = [x, y, z] # Center of the triangular facet
output.append(facet_center)
output = np.array(output).tolist()
return output
# ===================================================================
# ===================================================================
# ===================================================================
def ES_Fusion(set, structure, size=0):
# study the given set, and fusion some empty spheres to create a better set. Size is used for the partitionnal
# clustering, and structure assures the clustering will not reduce the distances. It it set basically to the min distance in the set.
if size == 0:
size = tool.shortest_dist(set)
# print("initial size :", size)
size = size * 11. / 10 # we add 10%, to include the very similar cases
# print("with error correction size :", size)
fusion_set = [] # output : defined like set
dmin = tool.set_set_proximity(set, structure)
hull = ConvexHull(structure)
# simplice_centers=Convex_Hull_Centers(structure+set)
while len(set) > 0:
# Define a new cluster, add as much empty spheres as possible, and regroup around the centroid
cluster = [set[0]]
centroid = cluster[0] # Initialisation of the next cluster (it may rest one element, to progress until set=void
set.pop(0)
reroll = 1
while reroll == 1:
d0_error = 0
reroll = 0 # We must scan the set everytime we change centroid, or we could miss some ES in set
for ES in set:
# Other possible condition : tool.point_set_proximity(ES, cluster)<=size
if tool.distance(ES, centroid) < size: # We can fusion to the cluster
reroll = 1 # Centroid will be updated, so reroll the scan of set
print("Fusionned a sphere to the cluster")
cluster.append(ES)
set.remove(ES) # It is in the cluster, so remove from set : we studied it
centroid = tool.Isobarycenter(cluster)
if tool.point_set_proximity(centroid,
structure) < dmin: # We have to put centroid farer to balance fusion
Nearest = tool.search_nearest(centroid, structure,
tool.point_set_proximity(centroid, structure))
V = np.ndarray.tolist(
np.array(centroid) - np.array(Nearest)) # So we need nearest structure point
d = tool.distance(centroid, Nearest)
if d == 0: # it means the centroid came right on existing structure
print("Cluster centered exactly in the structure. Size must be revised : cluster cancelled")
d0_error = 1
fusion_set += cluster
reroll = 0
break
else:
V = np.multiply(V, 1. / d) # set V as norm 1
V = np.multiply(V, dmin)
#
print("\n\n We put away form:\n{}\ndmin={}\n".format(tool.vector_norm(V), dmin))
#
centroid = np.ndarray.tolist(
np.array(Nearest) + V) # get centroid away from Nearest to dmin
#
#
#
if d0_error == 0:
fusion_set.append(centroid)
#
#
return fusion_set
# ===================================================================
def Fusion_Overlap(Spheres_Data, tol):
# Find Spheres touching each other, and fusions them. Don't return radius : only final coordinates
Output = []
ls = len(Spheres_Data)
Index = range(ls)
for iS in range(ls):
if iS in Index: # The we have to treat this case
FusionIndex = [iS]
for iOS in range(iS + 1, ls):
if iOS in Index:
S = Spheres_Data[iS][0]
OS = Spheres_Data[iOS][0]
rS = Spheres_Data[iS][1]
rOS = Spheres_Data[iOS][1]
# print("S : {}\nOS : {}".format(S,OS))
if tool.distance(S, OS) < (rS + rOS) * tol:
# print("Overlap detected : d= {}, r1 ={}, r2 = {}".format(tool.distance(S, OS),rS,rOS))
Index.remove(iOS) # S and OS are same coord or almost : we remove the last : OS
FusionIndex.append(iOS)
lf = len(FusionIndex)
x = y = z = 0
for i in FusionIndex:
x += Spheres_Data[i][0][0] / lf
y += Spheres_Data[i][0][1] / lf
z += Spheres_Data[i][0][2] / lf
Output.append([x, y, z])
# else : iS correspond to coord already fusionned
return Output
# ===================================================================
# ===================================================================
# ===================================================================
# ===================================================================
# ===================================================================
# ===================================================================
def Flat_Covering(Structure, R=0, tol=0.6, Curved=False):
# Designed for quite flat set : Searchs major plane, triangulates it, and cover both sides with empty spheres wich radius=size.
if R != 0:
NoAsk = 1
else:
NoAsk = 0
if Curved == False:
flatness = input("Please describe cluster :\nOnly one major plane : Enter 0\nMore major planes : Enter 1\n")
set = np.ndarray.tolist(Structure.positions)
struct = set
FlatCover = []
# Search major plane(s)
if flatness != 0:
AllPlanes = essyma.major_plane(struct, multiple=True)
else:
[Plane3D, Plane_eq] = essyma.major_plane(struct)
AllPlanes = [[Plane3D, Plane_eq]]
"""
for P in AllPlanes :
PlaneView = Atoms(positions=P[0])
#view(Structure+PlaneView)
view(PlaneView)
print("Plane n°{} : \nContains : {}\n PlaneEq = {}".format(AllPlanes.index(P)+1,P[0],P[1]))
#"""
# Build empty spheres for all major planes :
for AP in AllPlanes:
Plane3D, Plane_eq = AP
if NoAsk == 0:
Pview = Atoms(positions=Plane3D)
view(Pview)
print("Please select the radius of empty spheres you desire : ")
R = input("(See the view of current plane to get help)\n")
Index = []
for Ppt in Plane3D:
Index.append(struct.index(Ppt))
""" Show Details on Plane
#print("Plane : Equation is {}x+{}y+{}z+{}=0\n Plane norm is {}".format(Plane_eq[0],Plane_eq[1],Plane_eq[2],Plane_eq[3],Norm))
Lset = len(set)
name = "C" + str(Lset)
Structure = Atoms(name, positions=struct)
Plane3DView = Atoms(positions=Plane3D)
view(Structure + Plane3DView)
#""" # =====
Triang = Plane_Triangulation(Plane3D, Plane_eq)
# print("Triangulation 2D : {}".format(Triang.indices))
# Extract DataforTangent_Fourth_Sphere fromStructure
Data = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
simplicenters = []
for tria in Triang.indices:
Spheres_data = [Data[Index[tria[0]]], Data[Index[tria[1]]], Data[Index[tria[2]]]]
"""
h = (Spheres_data[0][1] + Spheres_data[1][1] + Spheres_data[2][1]) #h is set as 3 times the average covalent radii of atoms
xc = 1. / 3 * (Spheres_data[0][0][0] + Spheres_data[1][0][0] + Spheres_data[2][0][0])
yc = 1. / 3 * (Spheres_data[0][0][1] + Spheres_data[1][0][1] + Spheres_data[2][0][1])
zc = 1. / 3 * (Spheres_data[0][0][2] + Spheres_data[1][0][2] + Spheres_data[2][0][2])
Addpoint = np.ndarray.tolist(np.array([xc,yc,zc])+np.multiply(Norm,h))
Spheres_data.append([Addpoint,1]) # We add one sphere with radius=0, that must be tangent to solution
"""
P1, P2 = esclus.Triangle_ES(Spheres_data, R)
if P1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(R, [Index[tria[0]],
Index[tria[1]],
Index[tria[2]]]))
if P1 != 666:
FlatCover.append([P1, R])
FlatCover.append([P2, R])
"""
ViewPos=[Spheres_data[0][0],Spheres_data[1][0],Spheres_data[2][0],Addpoint,Cov1[0]]
print "preview :",ViewPos
Viewer=Atoms("H2OClX",positions=[Spheres_data[0][0],Spheres_data[1][0],Spheres_data[2][0],Addpoint,Cov1[0]])
view(Viewer)
Spheres_data.remove([Addpoint, 1])
Addpoint = np.ndarray.tolist(np.array([xc, yc, zc]) - np.multiply(Norm, h))
Spheres_data.append([Addpoint, 1]) # Our
print Spheres_data
Cov2 = esclus.Tetrahedron_ES (Spheres_data)
ViewPos = [Spheres_data[0][0], Spheres_data[1][0], Spheres_data[2][0], Addpoint, Cov2]
print "preview :", ViewPos
Viewer = Atoms("H2OClX", positions=[Spheres_data[0][0], Spheres_data[1][0], Spheres_data[2][0], Addpoint, Cov2[0]])
view(Viewer)
FlatCover.append(Cov1[0])
FlatCover.append(Cov2[0])
"""
"""
for tria in Triang.indices: #compute classic simplice center :
x=y=z=0
for vertex in tria:
x += set[vertex][0] / 3.0
y += set[vertex][1] / 3.0
z += set[vertex][2] / 3.0
simcen=[x,y,z]
for simcen in simplicenters :
C1=np.ndarray.tolist(np.array(simcen) + np.array(Norm))
C2=np.ndarray.tolist(np.array(simcen) - np.array(Norm))
FlatCover.append(C1)
FlatCover.append(C2)
#""" #
elif Curved == True: # With curve : Complicated to define planes... So we need to do as if it was pure 2D.
# In Case of Curved routine, ALL spheres will be included in Cover iteration.
FlatCover = []
Plane3D = Structure.positions
Plane2D = []
Projection_selected = 0
while Projection_selected == 0:
PProj = input(
"To create mesh, we need to project on a plane : please select him.\n1 for x=0\n2 for y=0\n3 for z=0\n")
if PProj == 1:
for pt in Plane3D:
Plane2D.append(pt[1:])
Projection_selected = 1
elif PProj == 3:
for pt in Plane3D:
Plane2D.append(pt[:2])
Projection_selected = 1
elif PProj == 2:
for pt in Plane3D:
Plane2D.append([pt[0], pt[2]])
Projection_selected = 1
Triang = delc.Triangulation(Plane2D)
if R == 0:
R = input("Please select the radius of empty spheres you desire : ")
Data = esclus.Spheres_Data_Structure_Extractor(Structure, 1)
simplicenters = []
for tria in Triang.indices:
Spheres_data = [Data[tria[0]], Data[tria[1]], Data[tria[2]]]
P1, P2 = esclus.Triangle_ES(Spheres_data, R)
if P1 == 666:
print("For radius {}, no solution of tangent to triangle {} ".format(R, [tria[0], tria[1],
tria[2]]))
if P1 != 666:
FlatCover.append([P1, R])
FlatCover.append([P2, R])
FlatCover = Fusion_Overlap(FlatCover, tol)
return FlatCover
# ====================================================================
def Plane_Triangulation(Plane3D, Plane_eq):
# Transform plane into same z
Norm = Plane_eq[:3]
a, b, c, d = Plane_eq
Plane2D = []
NormZ0 = [0, 0, 1]
Alpha = tool.angle_vector(Norm, NormZ0) # Angle of rotation
if Alpha % math.pi == 0: # Plane already at z=K : no rotation needed
for pt in Plane3D:
Plane2D.append(pt[:2])
else: # We must see the axis of rotation, then rotate all points :
if a == 0:
u = [1, 0, 0]
M = [-d / b, 0, 0]
else:
u = [-b / a, 1, 0]
M = [-d / a, 0, 0]
# print("Norm of Plane = {}, so : \nAlpha = {}° \nu={} and M = {}".format(Norm,Alpha * 180 / math.pi, u,M))
# Plane def by ax + by + cz + d = 0. Intercect z=0 at array ax + by + d = 0, so vector directing intercection is (-b,a,0)
nu = tool.vector_norm(u)
u = np.ndarray.tolist(np.multiply(u, 1. / nu))
# print("Intercection is line defined by vector u={} and point p={}\nAngle of rotation will be {}°".format(u,M,Alpha*180/math.pi))
# Now rotate all points with rotation angled Alpha round u.
Rview = []
for pt in Plane3D: # Translate point until axis of rotation include origin : for easier rotation
x, y, z = pt
Mm = [-M[0], -M[1], -M[2]]
pt = tool.vector_trslt(pt, Mm)
rpt = tool.rot3D(pt, Alpha, u)
rpt = tool.vector_trslt(rpt, M)
# print("pt = {}, rotate to rpt = {} (Verify same z !)".format(pt,rpt))
Rview.append(rpt)
Plane2D.append(rpt[:2])
# Triangulate with Delny : indices will be the same as original Plane : no need to invert transformation
Triang = delc.Triangulation(Plane2D)
return Triang
# ====================================================================
# ====================================================================
def Atom_Radius(Structure, n, list):
# Returns the radius of the n°th atom in Structure. 0 are placed to keep information. Unit = Angstrom
# List variable determines wich information we need
global ES_AllRadius
if 0 in Structure.numbers:
FirstES = np.ndarray.tolist(Structure.numbers).index(0) # Number of the first Empty_Spheres
N = Structure.numbers[n]
if N == 0: # Atom is X : empty sphere
Atom_Radius = ES_AllRadius[n - FirstES]
if list == 1: # Covalent Radii
Atom_Radius_List = covalent_radii
else:
print("No list found, verify list variable. Routine returns 0")
return 0
if Atom_Radius_List[N] == 0:
print ("No information on this atom, or false n° given. Routine returns 0")
return Atom_Radius_List[N]
# ===================================================================
def Convex_Hull_InterCover(set):
# Uses ConvexHull to find the triangular Hull from the set, then generate a covering by adding
# an empty sphere on each hull triangle.
# Returns list of cover coordinates
reverset = tool.Invert_Coord(set, [0, 0, 0], 2)
hull = ConvexHull(reverset)
cover_coord = []
counter = 0
for facet in hull.simplices: # hull.simplices contains index of simplices vertex, grouped by 3.
x = y = z = 0.0
for vertex in facet:
x += reverset[vertex][0] / 3.0
y += reverset[vertex][1] / 3.0
z += reverset[vertex][2] / 3.0
facet_center = [x, y, z] # Center of the triangular facet
normal_facet = hull.equations[counter][:3] # The exterior normal of the facet
addpoint = facet_center + normal_facet
cover_coord.append(addpoint)
counter += 1
cover_coord = np.array(cover_coord).tolist()
cover_coord = tool.Invert_Coord(cover_coord, [0, 0, 0], 2)
return cover_coord
# ===================================================================
def lookhull(Structure, hull):
# view the structure and his hull
hullview = []
for i in hull.vertices:
hullview.append(Structure.positions[i])
L = len(hullview)
Lookhull = Atoms(positions=hullview)
view(Lookhull)
view(Structure + Lookhull)
return 0