470 lines
23 KiB
Plaintext
470 lines
23 KiB
Plaintext
# coding: utf-8
|
|
|
|
============================================================
|
|
| Empty_Spheres Modules |
|
|
============================================================
|
|
|
|
Made by : Ulysse DUPONT
|
|
Collaboration with : Didier SEBILLEAU, Sylvain TRICOT
|
|
Helped by : Floris Bruynooghe (Delny) and the team from scipy.spatial (qhull/Voronoi)
|
|
|
|
Path : msspec/src/python/pymsspec/msspec/es
|
|
Language : Python
|
|
Important Global Variable : ES_AllRadius
|
|
|
|
============================================================
|
|
| About ES_AllRadius |
|
|
============================================================
|
|
|
|
For now : Empty spheres can be created from a cluster of Atoms.
|
|
The missing part is the definition of the Empty-Sphere Python Class : they are considered as "X" Atoms.
|
|
It means that the radius of empty spheres are not directly linked to them :
|
|
The routine empty-spheres.Atom_Radius(Structure,n,list) will recognize empty spheres because their atom number is 0.
|
|
So we created ES_AllRadius global variable, wich is updated after each EmptySphere generation with function
|
|
"ES_AllRadius_Updater(NewES,Structure)". The new radius are calculated brutally by taking the max, without touching
|
|
Structure molecules
|
|
|
|
To use this global variable, it will be necessary to delete no empty spheres (or be sure to delete the
|
|
correspondant radius in ES_AllRadius).
|
|
|
|
An example of ES_AllRadius use is given afterward : in the example "Covering GeCl4 using ES_AllRadius"
|
|
|
|
In the future, the informations about each empty-spheres radius can be taken directly in construction routines, and linked
|
|
to the empty-sphere python object.
|
|
|
|
|
|
============================================================
|
|
| Objectives |
|
|
============================================================
|
|
|
|
The empty_spheres modules are routines made to add empty spheres in clusters for diffusion computations.
|
|
The routines used are based on tetrahedralisation, convex-hull research and triangularisation to create adapted mesh,
|
|
and uses tangent-spheres resolutions to compute adapted coordinates and radius of empty-spheres
|
|
|
|
|
|
============================================================
|
|
| How to use ? |
|
|
============================================================
|
|
|
|
Before adding empty-spheres, you need a cluster, or list of positions.
|
|
The argument name "Structure" designs the Atoms type in pymsspec. The coordinates of the set of points is given
|
|
by the command : numpy.ndarray.tolist(Structure.positions)
|
|
|
|
For the moment, empty-sphere type isn't defined, only coordinates are computed.
|
|
|
|
To see how the routines work : We will show few examples : You just need to adjust the folder where the xyz files will be
|
|
|
|
|
|
__________________Internal/External ConvexHull Cover in C60_____________________________________________________________
|
|
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
Structure = read('cluster_examples/C60.xyz')
|
|
ExtCover = esph.Convex_Hull_Cover(Structure,radius_es=1,tol=1)
|
|
1
|
|
Result = Atoms(positions = ExtCover)
|
|
view(Structure + Result)
|
|
IntCover1 = esph.Internal_Hull_Cover(Structure,radius_es=0.84,tol=0.6)
|
|
l=len(IntCover1)
|
|
wcolor = "B"+str(l)
|
|
Result1 = Atoms(wcolor,positions = IntCover1)
|
|
view(Structure + Result1)
|
|
IntCover2 = esph.Internal_Hull_Cover(Structure + Result1)
|
|
|
|
Result2 = Atoms(positions = IntCover2)
|
|
view(Result1 + Result2)
|
|
view(Structure + Result1 + Result2)
|
|
=================================Comments :
|
|
|
|
The view will allow you to see the added spheres. For the moment, no empty spheres objects have been created,
|
|
so we defin special radii, from covalent radii table.
|
|
|
|
You can change IntCover1, for example taking radius_es = 0.71 and wcolor with "N" letter,
|
|
or es_radius = 0.76 and C letter,etc... The letter allow view function to set correct radii.
|
|
The tol parameter influences Fusion_Overlap. Spheres are fusionned if the distance beetween centers is less than
|
|
the sum of the two spheres raddi, multiplied by tol parameter. So tol=1 is used to completely avoid spheres to touch
|
|
themselves. Default value of tol has been subjectively settled at 0.6
|
|
|
|
ICover2 will ask for radius_es : it is not given in the function call.
|
|
If you put radius = 1.3, for example, you will obtain the centroid of the hull after fusionning the spheres.
|
|
Try very big or smaller radius to understand how fusion works.
|
|
____________________________________________________
|
|
|
|
|
|
|
|
__________________Delaunay TetraHedral with a cube face-centered________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
|
|
struct = struct = [[0,-1,0],[0,1,0],[0,0,1],[0,0,-1],[1,0,0],[-1,0,0],[-1,-1,-1],[1,-1,-1],[-1,1,-1],[1,1,-1],[-1,-1,1],[1,-1,1],[-1,1,1],[1,1,1]]
|
|
Structure = Atoms("C14",positions=struct)
|
|
set1 = esph.Delaunay_Tetrahedral_ES(Structure)
|
|
Set1 = Atoms (positions = set1)
|
|
view(Set1)
|
|
view(Structure + Set1)
|
|
|
|
set2 = esph.Delaunay_Tetrahedral_ES(Structure+Set1)
|
|
Set2 = Atoms (positions = set2)
|
|
view(Set2)
|
|
view(Structure + Set1 + Set2)
|
|
=================================Comments :
|
|
First iteration as you can see is given with np minsize and maxsize : This parameters are otionnaly set both at 0 and 999.
|
|
The second iteration will show you an actual problem :
|
|
The size of empty spheres must be saved to be used once more.
|
|
If free space is to small, the routine will obtain some unsolvable problems. This issue is showed in your board with
|
|
singular matrix
|
|
____________________________________________________
|
|
|
|
|
|
|
|
|
|
__________________Delaunay TetraHedral with a copper sample_____________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
Structure = read('cluster_examples/copper.xyz')
|
|
set1 = esph.Delaunay_Tetrahedral_ES(Structure)
|
|
Set1 = Atoms (positions = set1)
|
|
view(Set1)
|
|
view(Structure + Set1)
|
|
|
|
=================================Comments :
|
|
First iteration as you can see is given with np minsize and maxsize : This parameters are otionnaly set both at 0 and 999.
|
|
If you want to delete the empty-spheres added out of convexhull, you can add the parameter maxsize=2
|
|
No second iteration is done : see the centered cube example for explanations.
|
|
____________________________________________________
|
|
|
|
|
|
|
|
|
|
__________________Experiment problem of missing spheres in cover________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
struct = struct = [[0,-1,0],[0,1,0],[0,0,1],[0,0,-1],[1,0,0],[-1,0,0],[-1,-1,-1],[1,-1,-1],[-1,1,-1],[1,1,-1],[-1,-1,1],[1,-1,1],[-1,1,1],[1,1,1]]
|
|
Structure = Atoms("C14",positions=struct)
|
|
|
|
ExtCover = esph.Convex_Hull_Cover(Structure,radius_es=1,missing=True)
|
|
1
|
|
Result = Atoms(positions = ExtCover)
|
|
view(Structure + Result)
|
|
ExtCover = esph.Convex_Hull_Cover(Structure,radius_es=1)
|
|
1
|
|
Result = Atoms(positions = ExtCover)
|
|
view(Structure + Result)
|
|
=================================Comments :
|
|
As you will see : The Second Result show only 6 empty spheres, and this spheres could maybe overlap the centers of facets.
|
|
Classic ConveHull routine returns only boundary points of facets : if points are included in this facets, they miss...
|
|
To solve this problem : put the optionnal parameter "missing" at "True". Do it when your cluster as some huge facets with
|
|
some atoms included in (exactly like this cube facets, wich are centered).
|
|
The first result shows the "good way" : it solves the problem of atoms forgotten by ConvexHull routine.
|
|
____________________________________________________
|
|
|
|
|
|
|
|
__________________Covering Nanotube_____________________________________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
|
|
Structure = read('cluster_examples/tubes.xyz')
|
|
#set = np.ndarray.tolist(Structure.positions)
|
|
#hull=ConvexHull(set)
|
|
Cover = esph.Convex_Hull_Cover(Structure,radius_es=1,missing=True)
|
|
|
|
Result = Atoms(positions = Cover)
|
|
view(Structure + Result)
|
|
|
|
=================================Comments :
|
|
Computing time here is bigger, as you will see (Operation is done twice, if you need to go faster, you can do internal and
|
|
external cover in one same routine, by not using Select_Int_Ext function.
|
|
You can test routine with no missing parameter (missing=False by default) : You will feel good the problem of ConvexHull.
|
|
|
|
____________________________________________________
|
|
|
|
|
|
__________________Covering little NH3___________________________________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
Structure = read('cluster_examples/NH3.xyz')
|
|
|
|
|
|
FCover = esph.Flat_Covering(Structure)
|
|
1
|
|
3
|
|
Result = Atoms(positions = FCover)
|
|
view(Structure + Result)
|
|
|
|
Cover = esph.Convex_Hull_Cover(Structure)
|
|
1
|
|
1
|
|
Result = Atoms(positions = Cover)
|
|
view(Structure + Result)
|
|
|
|
TCover = esph.Delaunay_Tetrahedral_ES(Structure)
|
|
Result = Atoms(positions = TCover)
|
|
view(Structure + Result)
|
|
=================================Comments :
|
|
Using Flat Covening in caseof little molecule can let some problems : the "biggest plane" selected isn't H3, but an NH2
|
|
face. The results you would prefer are obtained in Convex_Hull_Cover : with a small radius (1 for example), overlap will
|
|
happen and routine computes only the empty sphere on the other side of H3 face. With bigger radius (try 2), you will
|
|
obtain 3 empty spheres.
|
|
TCover uses Tetrahedral resolution. But this problem set a radius solution of polygon with delta < 0, ie no solution is
|
|
computed
|
|
|
|
|
|
|
|
__________________Covering GeCl4 using ES_AllRadius global variable_____________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
|
|
Structure = read('cluster_examples/GeCl4.xyz')
|
|
Cover = esph.Convex_Hull_Cover(Structure,radius_es=2)
|
|
1
|
|
Result = Atoms(positions = Cover)
|
|
view(Structure+Result)
|
|
|
|
ESAR1=esph.ES_AllRadius_Updater(Result,Structure,list=1)
|
|
print("Actual ES radius list (ESAR1) :\n{}".format(ESAR1))
|
|
Structure=Structure+Result
|
|
|
|
Cover = esph.Convex_Hull_Cover(Structure,radius_es=3.5,tol=0)
|
|
1
|
|
Result = Atoms(positions = Cover)
|
|
view(Structure+Result)
|
|
|
|
ESAR2=esph.ES_AllRadius_Updater(Result,Structure,list=1)
|
|
print("Actual ES radius list (ESAR2) :\n{}".format(ESAR2))
|
|
comp1=ESAR2[-1]
|
|
Cover = esph.Convex_Hull_Cover(Structure,radius_es=3.5)
|
|
1
|
|
Result = Atoms(positions = Cover)
|
|
view(Structure+Result)
|
|
|
|
ESAR2bis=esph.ES_AllRadius_Updater(Result,Structure,list=1)
|
|
comp2=ESAR2bis[-1]
|
|
print("\n\nWithout fusioning 2nd Cover, empty spheres are sized {} , after fusion there radius is {}".format(comp1,comp2))
|
|
|
|
|
|
=================================Comments :
|
|
ESAR1 and ESAR2 are just copy in time of the global variable "ES_AllRadius". Indeed : this global variable is used in
|
|
empty_spheres.py, not in main. So ES_AllRadius_Updater returns the global variable in the time it is called.
|
|
|
|
We also use this example to show tol use : in the second covering, we need a big radius to touch the 3 bounds of triangle
|
|
vertices, so afterward the empty spheres are overlapping. So without tol parameter (tol=0.6 by default), the empty-spheres
|
|
fusion, and the second cover is aligned with Cl atoms.
|
|
With tol = 0 , no fusion is done, so we have more empty spheres in cover.
|
|
Comparing the size of spheres with and without fusionning, you can see that fusion isn't always a good solution.
|
|
|
|
|
|
|
|
__________________Covering molecule Phtalocyanine_______________________________________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
from scipy.spatial import ConvexHull
|
|
|
|
Structure = read('cluster_examples/phtalocyanine.xyz')
|
|
view(Structure)
|
|
FCover = esph.Flat_Covering(Structure,R=2)
|
|
|
|
Result = Atoms(positions = FCover)
|
|
view(Structure + Result)
|
|
FCover = esph.Flat_Covering(Structure,Curved=True)
|
|
|
|
Result = Atoms(positions = FCover)
|
|
view(Structure + Result)
|
|
=================================Comments :
|
|
The first FCover is using classic "FlatCovering" : the routine search for every plane, then triangulate and add ES.
|
|
The problem here is that phtalocyanine is curved : so the polygons we see are not in same plane !
|
|
As command : Enter 1 to tell there are a lot of different planes.
|
|
To see the planes constructed, remove the R=2 parameter. Don't be afraid about time taken in this routine (5min possible)
|
|
|
|
To solve the problem : we add the "Curved=True" : as the cluster is close to z=0 plane (but curved), we project him as
|
|
2D plane with z=0. So we can triangulate correctly. Be careful with this method : all spheres are taken in the mesh !
|
|
As radius, you should select 1.5, and do again with 2 : The results are pretty different because of the overlap : it can
|
|
be interesting to compare the results.
|
|
|
|
|
|
|
|
__________________Computin Voronoi Vertices of a Structure (face-centered cube)_________________________________________
|
|
=================================Commands :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
from ase.visualize import view
|
|
from es_mod import empty_spheres as esph
|
|
Structure = read('cluster_examples/centeredcube.xyz')
|
|
Vor=esph.Voronoi_Vertex(Structure)
|
|
Result=Atoms(positions=Vor)
|
|
view(Structure+Result)
|
|
Structure = read('cluster_examples/GeCl4.xyz')
|
|
Vor=esph.Voronoi_Vertex(Structure)
|
|
Result=Atoms(positions=Vor)
|
|
view(Structure+Result)
|
|
Structure = read('cluster_examples/tubes.xyz')
|
|
Vor=esph.Voronoi_Vertex(Structure)
|
|
Result=Atoms(positions=Vor)
|
|
view(Structure)
|
|
view(Structure+Result)
|
|
=================================Commands for complete Voronoi informations (ridges, regions/polyhedrons) :
|
|
from ase import Atoms
|
|
from ase.io import write,read
|
|
import numpy as np
|
|
from scipy.spatial import Voronoi
|
|
|
|
Structure = read('cluster_examples/centeredcube.xyz')
|
|
Str=np.ndarray.tolist(Structure.positions)
|
|
Vor = Voronoi(Str)
|
|
|
|
Vor. [Then click on Tab]
|
|
=================================Comments :
|
|
The Voronoi_Vertex routine uses scipy.spatial.Voronoi :
|
|
https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.spatial.Voronoi.html
|
|
|
|
You can use commands for complete Voronoi information to get voronoi ridges, regions, etc (see details after clicking Tab)
|
|
|
|
As you can see, the Voronoi research is very similar to the research of empty spheres. But the common errors solved
|
|
before will happen here to (see the 2 last figures : example with nanotube)
|
|
|
|
Other Voronoi Tesselations can be found under C++ opensource Voro++ : http://math.lbl.gov/voro++/about.html
|
|
|
|
========================================================================================================================
|
|
========================================================================================================================
|
|
|
|
|
|
============================================================
|
|
| Routines |
|
|
============================================================
|
|
|
|
The Empty_Spheres routines are agenced in different folders :
|
|
|
|
=====================empty_spheres.py=========================
|
|
|
|
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],[Int_Ext]) : 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_clustering.py=========================
|
|
Tangent_Fourth_Sphere(Spheres_data, r, inout=1) : From 3 tangent spheres, returns the fourth, tangent to others, with radius r.
|
|
inout determines the side of the coordinate.
|
|
Spheres_Data_Structure_Extractor (Structure,list) : From Structure, returns data as [[S1][S2]...] where Si = [[xi,yi,zi],ri]
|
|
used in Tangent_Fourth routine. List determines the radius we will use.
|
|
|
|
Spheres_Data_XYZ_Extractor (name,list) : From name, given as "_____.xyz", returns data as [[S1][S2]...] where Si = [[xi,yi,zi],ri]
|
|
used in Tangent_Fourth routine. List determines the radius we will use.
|
|
|
|
Tetrahedron_ES (Spheres_data) : From 4 spheres forming a tetrahedron,returns the sphere tangent to others, with radius r.
|
|
|
|
Triangle_ES (Spheres_data,R) : Returns the 2 solutions of tangent of 3 spheres with radius R.
|
|
==============================================================
|
|
========================es_tools.py===========================
|
|
=================Vector tools==================
|
|
vector_def(A,B) : returns simply the vector translating A to B
|
|
vector_norm(V) : return euclidian norm of a vector
|
|
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)
|
|
=====================es_sym_analys.py=========================
|
|
sym_analyse(Cluster) : Convert set into xyz folder, then finds all symetries using. Uses compare_sym and read_sym_file
|
|
|
|
major_plane(set) : Search the major plane with max nb of points in set and returns all of his points, and his equation
|
|
|
|
Cluster_flatness_informations(set) : Returns set's hull's total volume and area
|
|
|
|
Cluster_search_hollow(set,tol) : Returns the hollow datas : hollow=[[list,center,volume]...] where list is hollow' vertice's
|
|
|
|
Cluster_emptyness_informations(structure) : Returns the % of volume of hull occupied by his spheres index,[center,volume] his hollow's center and volume. tol defines hollow's diagonale
|
|
|
|
Vertice_Sphere_Proportion(O,hull) : Returns the proportion of the sphere centered in Oth pt in the hull (proportion in ]O,1])
|
|
|
|
hull_search_neighbors(O,Simplices) : Returns list including O and neighbors (list contains only index, no coordinates)
|
|
|
|
convex_base(Neil,Simplices) : Returns all Neil[0] neighbors so as ConvBase is the base of pyramid from top Neil[0]
|
|
|
|
Neighbors_List(numAtom,Structure) : Returns index list in Structure of neighbors of Atom indexed numAtom. numatom not included
|
|
|
|
Hull_Tetracut(O,Structure,hull) : Returns index list in Structure of centers of spheres defining the terahedron cuting the vertice O
|
|
|
|
facet_cap(O,Structure,hull) : Return the proportion of sphere centered in O out from the hull(ie return the cap proportion of the sphere defined by cuting sphere with hull facets)
|
|
==============================================================
|
|
|
|
|
|
|
|
|
|
|
|
|