root / ase / embed.py @ 5
Historique | Voir | Annoter | Télécharger (9,87 ko)
1 | 2 | tkerber | from ase import Atom, Atoms |
---|---|---|---|
2 | 2 | tkerber | from ase.data import covalent_radii, atomic_numbers |
3 | 2 | tkerber | |
4 | 2 | tkerber | import numpy as np |
5 | 2 | tkerber | |
6 | 2 | tkerber | class Embed(Atoms): |
7 | 2 | tkerber | #--- constructor of the Embed class ---
|
8 | 2 | tkerber | def __init__(self, system=None, cluster=None): |
9 | 2 | tkerber | super(Embed, self).__init__() |
10 | 2 | tkerber | # define the atom map
|
11 | 2 | tkerber | self.atom_map_sys_cl = []
|
12 | 3 | tkerber | self.atom_map_cl_sys = []
|
13 | 2 | tkerber | self.linkatoms = []
|
14 | 2 | tkerber | # cluster dimensions
|
15 | 2 | tkerber | self.xyz_cl_min = None |
16 | 2 | tkerber | self.xyz_cl_max = None |
17 | 2 | tkerber | # set the search radius for link atoms
|
18 | 3 | tkerber | self.d = 10 |
19 | 2 | tkerber | # define the systems for calculations
|
20 | 2 | tkerber | self.set_system(system)
|
21 | 2 | tkerber | self.set_cluster(cluster)
|
22 | 2 | tkerber | #
|
23 | 2 | tkerber | self.set_cell([10, 10, 10]) |
24 | 2 | tkerber | return
|
25 | 3 | tkerber | |
26 | 3 | tkerber | #--- set the cluster ---
|
27 | 2 | tkerber | def set_cluster(self, atoms): |
28 | 2 | tkerber | import copy |
29 | 2 | tkerber | # set the min/max cluster dimensions
|
30 | 2 | tkerber | self.xyz_cl_min = atoms[0].get_position() |
31 | 2 | tkerber | self.xyz_cl_max = atoms[0].get_position() |
32 | 2 | tkerber | for atom in atoms: |
33 | 2 | tkerber | # assign the label "Cluster (10)" in atom.TAG
|
34 | 2 | tkerber | atom.set_tag(10)
|
35 | 2 | tkerber | xyz=atom.get_position() |
36 | 2 | tkerber | for i in xrange(3): |
37 | 2 | tkerber | # set the min/max cluster dimensions
|
38 | 2 | tkerber | if xyz[i] < self.xyz_cl_min[i]: |
39 | 2 | tkerber | self.xyz_cl_min[i] = xyz[i]
|
40 | 2 | tkerber | if xyz[i] > self.xyz_cl_max[i]: |
41 | 2 | tkerber | self.xyz_cl_max[i] = xyz[i]
|
42 | 3 | tkerber | |
43 | 2 | tkerber | # add self.d around min/max cluster dimensions
|
44 | 2 | tkerber | self.xyz_cl_min -= [self.d, self.d, self.d] |
45 | 3 | tkerber | self.xyz_cl_max += [self.d, self.d, self.d] |
46 | 2 | tkerber | # set the cluster for low and high level calculation
|
47 | 2 | tkerber | self.atoms_cluster = atoms
|
48 | 2 | tkerber | return
|
49 | 2 | tkerber | |
50 | 2 | tkerber | #--- set the system ---
|
51 | 2 | tkerber | def set_system(self, atoms): |
52 | 3 | tkerber | self.atoms_system = atoms
|
53 | 2 | tkerber | # assign the label "Cluster (10)" in atom.TAG
|
54 | 2 | tkerber | for atom in atoms: |
55 | 2 | tkerber | atom.set_tag(0)
|
56 | 2 | tkerber | # update search radius for link atoms
|
57 | 2 | tkerber | dx = 0
|
58 | 2 | tkerber | for atom in atoms: |
59 | 2 | tkerber | r = covalent_radii[atom.get_atomic_number()] |
60 | 2 | tkerber | if (r > dx):
|
61 | 2 | tkerber | dx = r |
62 | 2 | tkerber | self.d = dx * 2.1 |
63 | 2 | tkerber | return
|
64 | 3 | tkerber | |
65 | 2 | tkerber | #--- return cluster ---
|
66 | 2 | tkerber | def get_cluster(self): |
67 | 2 | tkerber | return self.atoms_cluster |
68 | 3 | tkerber | |
69 | 2 | tkerber | def get_system(self): |
70 | 2 | tkerber | return self.atoms_system |
71 | 3 | tkerber | |
72 | 2 | tkerber | #--- Embedding ---
|
73 | 2 | tkerber | def embed(self): |
74 | 2 | tkerber | # is the cluster and the host system definied ?
|
75 | 2 | tkerber | if self.atoms_cluster is None or self.atoms_system is None: |
76 | 2 | tkerber | return
|
77 | 2 | tkerber | self.find_cluster()
|
78 | 2 | tkerber | self.set_linkatoms()
|
79 | 2 | tkerber | print "link atoms found: ", len(self.linkatoms) |
80 | 2 | tkerber | |
81 | 2 | tkerber | def find_cluster(self): |
82 | 2 | tkerber | # set tolerance
|
83 | 2 | tkerber | d = 0.001
|
84 | 2 | tkerber | #atoms
|
85 | 2 | tkerber | xyzs_cl=[] |
86 | 2 | tkerber | for atom_cl in self.atoms_cluster: |
87 | 2 | tkerber | xyzs_cl.append(atom_cl.get_position()) |
88 | 2 | tkerber | xyzs_sys=[] |
89 | 2 | tkerber | for atom_sys in self.atoms_system: |
90 | 2 | tkerber | xyzs_sys.append(atom_sys.get_position()) |
91 | 3 | tkerber | |
92 | 3 | tkerber | self.atom_map_sys_cl = np.zeros(len(self.atoms_system), int) |
93 | 3 | tkerber | self.atom_map_cl_sys = np.zeros(len(self.atoms_cluster), int) |
94 | 3 | tkerber | # loop over cluster atoms atom_sys
|
95 | 2 | tkerber | for iat_sys in xrange(len(self.atoms_system)): |
96 | 2 | tkerber | # get the coordinates of the system atom atom_sys
|
97 | 2 | tkerber | xyz_sys = xyzs_sys[iat_sys] |
98 | 2 | tkerber | # bSysOnly: no identical atom has been found
|
99 | 2 | tkerber | bSysOnly = True
|
100 | 2 | tkerber | # loop over system atoms atom_cl
|
101 | 2 | tkerber | for iat_cl in xrange(len(self.atoms_cluster)): |
102 | 2 | tkerber | # difference vector between both atoms
|
103 | 2 | tkerber | xyz_diff = np.abs(xyzs_sys[iat_sys]-xyzs_cl[iat_cl]) |
104 | 2 | tkerber | # identical atoms
|
105 | 2 | tkerber | if xyz_diff[0] < d and xyz_diff[1] < d and xyz_diff[2] < d: |
106 | 2 | tkerber | # set tag (CLUSTER+HOST: 10) to atom_sys
|
107 | 2 | tkerber | self.atoms_system[iat_sys].set_tag(10) |
108 | 2 | tkerber | # map the atom in the atom list
|
109 | 3 | tkerber | self.atom_map_sys_cl[iat_sys] = iat_cl
|
110 | 3 | tkerber | self.atom_map_cl_sys[iat_cl] = iat_sys
|
111 | 2 | tkerber | # atom has been identified
|
112 | 2 | tkerber | bSysOnly = False
|
113 | 2 | tkerber | break
|
114 | 2 | tkerber | if bSysOnly:
|
115 | 2 | tkerber | self.atom_map_sys_cl[iat_sys] = -1 |
116 | 2 | tkerber | |
117 | 2 | tkerber | def set_linkatoms(self, tol=15., linkAtom=None, debug=False): |
118 | 2 | tkerber | # local copies of xyz coordinates to avoid massive copying of xyz objects
|
119 | 2 | tkerber | xyzs_cl=[] |
120 | 2 | tkerber | for atom_cl in self.atoms_cluster: |
121 | 2 | tkerber | xyzs_cl.append(atom_cl.get_position()) |
122 | 2 | tkerber | xyzs_sys=[] |
123 | 2 | tkerber | for atom_sys in self.atoms_system: |
124 | 3 | tkerber | xyzs_sys.append(atom_sys.get_position()) |
125 | 2 | tkerber | # FIXME: mapping does not work when cluster atoms are outside of the box
|
126 | 2 | tkerber | # set the standard link atom
|
127 | 2 | tkerber | if linkAtom is None: |
128 | 2 | tkerber | linkAtom ='H'
|
129 | 2 | tkerber | # number of atoms in the cluster and the system
|
130 | 2 | tkerber | nat_cl=len(self.atoms_cluster) |
131 | 2 | tkerber | nat_sys=len(self.atoms_system) |
132 | 2 | tkerber | # system has pbc?
|
133 | 3 | tkerber | pbc = self.get_pbc()
|
134 | 2 | tkerber | # set the bond table
|
135 | 2 | tkerber | bonds = [] |
136 | 2 | tkerber | # set the 27 cell_vec, starting with the (0,0,0) vector for the unit cell
|
137 | 2 | tkerber | cells_L = [(0.0, 0.0, 0.0)] |
138 | 2 | tkerber | # get the cell vectors
|
139 | 2 | tkerber | cell = self.get_cell()
|
140 | 2 | tkerber | # TODO: check 0D, 1D, 2D, 3D
|
141 | 2 | tkerber | if False: |
142 | 2 | tkerber | for ix in xrange(-1, 2): |
143 | 2 | tkerber | for iy in xrange(-1, 2): |
144 | 2 | tkerber | for iz in xrange(-1, 2): |
145 | 2 | tkerber | if ix == 0 and iy == 0 and iz == 0: |
146 | 2 | tkerber | continue
|
147 | 2 | tkerber | |
148 | 2 | tkerber | cells_L.append(np.dot([ix, iy, iz], cell)) |
149 | 2 | tkerber | # save the radius of system atoms
|
150 | 2 | tkerber | rs_sys = [] |
151 | 2 | tkerber | for atom in self.atoms_system: |
152 | 2 | tkerber | rs_sys.append(covalent_radii[atom.get_atomic_number()]) |
153 | 2 | tkerber | # sum over cluster atoms (iat_cl)
|
154 | 2 | tkerber | for iat_cl in xrange(nat_cl): |
155 | 2 | tkerber | # get the cluster atom
|
156 | 2 | tkerber | atom_cl=self.atoms_cluster[iat_cl]
|
157 | 2 | tkerber | # ignore link atoms
|
158 | 2 | tkerber | if atom_cl.get_tag() == 50: |
159 | 2 | tkerber | continue
|
160 | 2 | tkerber | # xyz coordinates and covalent radius of the cluster atom iat_cl
|
161 | 2 | tkerber | xyz_cl = xyzs_cl[iat_cl] |
162 | 2 | tkerber | r_cl = covalent_radii[atom_cl.get_atomic_number()] |
163 | 3 | tkerber | |
164 | 2 | tkerber | # sum over system atoms (iat_sys)
|
165 | 2 | tkerber | for iat_sys in xrange(nat_sys): |
166 | 2 | tkerber | # avoid cluster atoms
|
167 | 2 | tkerber | if self.atoms_system[iat_sys].get_tag()==10: |
168 | 2 | tkerber | continue
|
169 | 2 | tkerber | # sum over all cell_L
|
170 | 2 | tkerber | for cell_L in cells_L: |
171 | 2 | tkerber | # xyz coordinates and covalent radius of the system atom iat_sys
|
172 | 2 | tkerber | xyz_sys = xyzs_sys[iat_sys]+cell_L |
173 | 2 | tkerber | # go only in distance self.d around the cluster
|
174 | 2 | tkerber | lcont = True
|
175 | 2 | tkerber | for i in xrange(3): |
176 | 3 | tkerber | if (xyz_sys[i] < self.xyz_cl_min[i] or |
177 | 2 | tkerber | xyz_sys[i] > self.xyz_cl_max[i]):
|
178 | 2 | tkerber | lcont = False
|
179 | 2 | tkerber | break
|
180 | 2 | tkerber | if not lcont: |
181 | 2 | tkerber | continue
|
182 | 2 | tkerber | # xyz coordinates and covalent radius of the system atom iat_sys
|
183 | 2 | tkerber | r_sys = rs_sys[iat_sys] |
184 | 2 | tkerber | # diff vector
|
185 | 2 | tkerber | xyz_diff = xyz_sys - xyz_cl |
186 | 2 | tkerber | # distance between the atoms
|
187 | 2 | tkerber | r = np.sqrt(np.dot(xyz_diff, xyz_diff)) |
188 | 2 | tkerber | # ratio of the distance to the sum of covalent radius
|
189 | 2 | tkerber | f = r / (r_cl + r_sys) |
190 | 2 | tkerber | if debug:
|
191 | 2 | tkerber | print "Covalent radii = ",r_cl, r_sys |
192 | 2 | tkerber | print "Distance ", f |
193 | 2 | tkerber | print "tol = ",(1+tol/100.),(1-tol/100.),(1-2*tol/100.) |
194 | 2 | tkerber | if f <= (1+tol/100.) and f >= (1-2*tol/100.): |
195 | 3 | tkerber | s = cell_L, self.atom_map_cl_sys[iat_cl], iat_sys, r_cl
|
196 | 2 | tkerber | bonds.append(s) |
197 | 2 | tkerber | break
|
198 | 2 | tkerber | if f <= (1-2*tol/100.): |
199 | 2 | tkerber | raise RuntimeError("QMX: The cluster atom", iat_cl, " and the system atom", iat_sys, "came too close") |
200 | 3 | tkerber | |
201 | 2 | tkerber | r_h = covalent_radii[atomic_numbers[linkAtom]] |
202 | 2 | tkerber | for bond in bonds: |
203 | 3 | tkerber | cell_L, iat_cl_sys, iat_sys, r_cl = bond |
204 | 2 | tkerber | # assign the tags for the border atoms
|
205 | 2 | tkerber | atom_sys.set_tag(1)
|
206 | 2 | tkerber | atom_cl.set_tag(11)
|
207 | 2 | tkerber | #difference vector for the link atom, scaling
|
208 | 3 | tkerber | xyz_diff = xyzs_sys[iat_sys] + cell_L - xyzs_sys[iat_cl_sys] |
209 | 2 | tkerber | r = (r_cl + r_h) |
210 | 2 | tkerber | xyz_diff *= r / np.sqrt(np.dot(xyz_diff, xyz_diff)) |
211 | 2 | tkerber | # determine position of the link atom
|
212 | 3 | tkerber | xyz_diff += xyzs_sys[iat_cl_sys] |
213 | 2 | tkerber | # create link atom
|
214 | 2 | tkerber | atom = Atom(symbol=linkAtom, position=xyz_diff, tag=50)
|
215 | 2 | tkerber | # add atom to cluster
|
216 | 2 | tkerber | self.atoms_cluster.append(atom)
|
217 | 2 | tkerber | # add atom to the linkatoms
|
218 | 3 | tkerber | s = cell_L, iat_cl_sys, iat_sys, r, len(self.atoms_cluster)-1 |
219 | 2 | tkerber | self.linkatoms.append(s)
|
220 | 2 | tkerber | return
|
221 | 3 | tkerber | |
222 | 2 | tkerber | def set_positions(self, positions_new): |
223 | 2 | tkerber | # number of atoms
|
224 | 2 | tkerber | nat_sys=len(self.atoms_system) |
225 | 2 | tkerber | # go over all pairs of atoms
|
226 | 2 | tkerber | for iat_sys in xrange(nat_sys): |
227 | 2 | tkerber | xyz = positions_new[iat_sys] |
228 | 5 | tkerber | self.atoms_system[iat_sys].set_position(xyz)
|
229 | 2 | tkerber | iat_cl = self.atom_map_sys_cl[iat_sys]
|
230 | 2 | tkerber | if iat_cl > -1: |
231 | 2 | tkerber | self.atoms_cluster[iat_cl].set_position(xyz)
|
232 | 3 | tkerber | |
233 | 3 | tkerber | for cell_L, iat_cl_sys, iat_sys, r, iat in self.linkatoms: |
234 | 2 | tkerber | # determine position of the link atom
|
235 | 5 | tkerber | xyz_cl = positions_new[iat_cl_sys] |
236 | 5 | tkerber | xyz = positions_new[iat_sys] - xyz_cl + cell_L |
237 | 2 | tkerber | xyz *= r / np.sqrt(np.dot(xyz, xyz)) |
238 | 2 | tkerber | xyz += xyz_cl |
239 | 2 | tkerber | # update xyz coordinates of the cluster
|
240 | 2 | tkerber | self.atoms_cluster[iat].set_position(xyz)
|
241 | 3 | tkerber | |
242 | 2 | tkerber | def __getitem__(self, i): |
243 | 2 | tkerber | return self.atoms_system.__getitem__(i) |
244 | 2 | tkerber | |
245 | 2 | tkerber | def get_positions(self): |
246 | 2 | tkerber | return self.atoms_system.get_positions() |
247 | 3 | tkerber | |
248 | 2 | tkerber | def __add__(self, other): |
249 | 2 | tkerber | return self.atoms_system.__add__(other) |
250 | 3 | tkerber | |
251 | 2 | tkerber | def __delitem__(self, i): |
252 | 2 | tkerber | return self.atoms_system.__delitem__(i) |
253 | 3 | tkerber | |
254 | 2 | tkerber | def __len__(self): |
255 | 2 | tkerber | return self.atoms_system.__len__() |
256 | 3 | tkerber | |
257 | 3 | tkerber | def get_chemical_symbols(self, reduce=False): |
258 | 3 | tkerber | return self.atoms_system.get_chemical_symbols(reduce) |